Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
#include "tfarmserver.h"
#include "tfarmexecutor.h"
#include "tfarmcontroller.h"
#include "tthreadmessage.h"
#include "tthread.h"
#include "tsystem.h"
#include "tsmartpointer.h"
#include "service.h"
#include "tlog.h"
#include "tfilepath_io.h"
#include "tcli.h"
#include "tversion.h"
using namespace TVER;
#include <string>
#include <map>
#include <sstream>
#include <QString>
#include <QProcess>
#include <QCoreApplication>
#include <QEventLoop>
#include "tthread.h"
#ifdef _WIN32
#include <iostream>
#else
#include <sys/param.h>
#include <unistd.h>
#endif
//#define REDIRECT_OUTPUT
#ifdef _WIN32
#define QUOTE_STR "\""
#define CASMPMETER "casmpmeter.exe"
#else
#define QUOTE_STR "'"
#define CASMPMETER "casmpmeter"
#endif
#ifndef _WIN32
#define NO_ERROR 0
#endif
// forward declaration
class FarmServer;
//-------------------------------------------------------------------
namespace {
//--------------------------------------------------------------------
TFilePath getGlobalRoot() {
TVER::ToonzVersion tver;
TFilePath rootDir;
#ifdef _WIN32
std::string regpath = "SOFTWARE\\" + tver.getAppName() + "\\" +
tver.getAppName() + "\\" + tver.getAppVersionString() +
"\\FARMROOT";
TFilePath name(regpath);
rootDir = TFilePath(TSystem::getSystemValue(name).toStdString());
#else
// Leggo la localRoot da File txt
#ifdef MACOSX
// If MACOSX, change to MACOSX path
std::string unixpath = "./" + tver.getAppName() +
".app/Contents/Resources/configfarmroot.txt";
#else
// set path to something suitable for most linux (Unix?) systems
std::string unixpath = "/etc/" + tver.getAppName() + "/opentoonz.conf";
#endif
TFilePath name(unixpath);
Tifstream is(name);
if (is) {
char line[1024];
is.getline(line, 80);
char *s = line;
while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\"') s++;
if (*s != '\0') {
char *t = s;
while (*t) t++;
std::string pathName(s, t - 1);
rootDir = TFilePath(pathName);
}
}
#endif
return rootDir;
}
//--------------------------------------------------------------------
TFilePath getLocalRoot() {
TVER::ToonzVersion tver;
TFilePath lroot;
#ifdef _WIN32
QString regpath = QString::fromStdString(
"SOFTWARE\\" + tver.getAppName() + "\\" + tver.getAppName() + "\\" +
tver.getAppVersionString() + "\\FARMROOT");
TFilePath name(regpath);
lroot = TFilePath(TSystem::getSystemValue(name).toStdString()) +
TFilePath("toonzfarm");
#else
#ifdef MACOSX
// If MACOSX, change to MACOSX path
std::string unixpath = "./" + tver.getAppName() +
".app/Contents/Resources/configfarmroot.txt";
#else
// set path to something suitable for most linux (Unix?) systems
#ifdef FREEBSD
std::string unixpath = "/usr/local/etc/" + tver.getAppName() + "/opentoonz.conf";
#else
std::string unixpath = "/etc/" + tver.getAppName() + "/opentoonz.conf";
#endif
#endif
TFilePath name(unixpath);
Tifstream is(name);
if (is) {
char line[1024];
is.getline(line, 80);
char *s = line;
while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\"') s++;
if (*s != '\0') {
char *t = s;
while (*t) t++;
std::string pathName(s, t - 1);
lroot = TFilePath(pathName);
}
}
#endif
return lroot;
}
//--------------------------------------------------------------------
TFilePath getBinRoot() {
#ifdef _WIN32
return TSystem::getBinDir();
#else
return getLocalRoot() + "bin";
#endif
}
//--------------------------------------------------------------------
bool dirExists(const TFilePath &dirFp) {
bool exists = false;
#ifdef _WIN32
TFileStatus fs(dirFp);
exists = fs.isDirectory();
#else
int acc = access(::to_string(dirFp).c_str(), 00); // 00 == solo esistenza
exists = acc != -1;
#endif
return exists;
}
//--------------------------------------------------------------------
bool myDoesExists(const TFilePath &fp) {
bool exists = false;
#ifdef _WIN32
TFileStatus fs(fp);
exists = fs.doesExist();
#else
int acc = access(::to_string(fp).c_str(), 00); // 00 == solo esistenza
exists = acc != -1;
#endif
return exists;
}
//-----------------------------------------------------------------------------
inline bool isBlank(char c) { return c == ' ' || c == '\t' || c == '\n'; }
} // anonymous namespace
//==============================================================================
//==============================================================================
class FarmServerService final : public TService {
public:
FarmServerService(std::ostream &os)
: TService("ToonzFarm Server", "ToonzFarm Server")
, m_os(os)
, m_userLog(0) {}
~FarmServerService() { delete m_userLog; }
void onStart(int argc, char *argv[]) override;
void onStop() override;
void loadControllerData(QString &hostName, std::string &ipAddr, int &port);
#ifdef _WIN32
void loadDiskMountingPoints(const TFilePath &fp);
void mountDisks();
void unmountDisks();
std::map<std::string, std::string> m_disks;
std::vector<std::string> m_disksMounted;
#endif
int m_port;
QString m_addr;
FarmServer *m_farmServer;
std::ostream &m_os;
TUserLog *m_userLog;
};
FarmServerService service(std::cout);
//==============================================================================
//==============================================================================
class FarmControllerProxy final : public TSmartObject {
TFarmController *m_controller;
public:
FarmControllerProxy(TFarmController *controller) : m_controller(controller) {}
~FarmControllerProxy() { delete m_controller; }
TFarmController *getController() const { return m_controller; }
private:
// not implemented
FarmControllerProxy(const FarmControllerProxy &);
FarmControllerProxy &operator=(const FarmControllerProxy &);
};
// non posso usare lo smartpointer di tnzcore perche' non linka su .NET
class FarmControllerProxyP {
FarmControllerProxy *m_proxy;
public:
FarmControllerProxyP() : m_proxy(0) {}
~FarmControllerProxyP() {
if (m_proxy) m_proxy->release();
}
FarmControllerProxyP(const FarmControllerProxyP &src) : m_proxy(src.m_proxy) {
if (m_proxy) m_proxy->addRef();
}
FarmControllerProxyP &operator=(const FarmControllerProxyP &src) {
FarmControllerProxyP tmp(*this);
std::swap(tmp.m_proxy, m_proxy);
return *this;
}
FarmControllerProxyP &operator=(TFarmController *controller) {
if (m_proxy && m_proxy->getController() == controller) return *this;
if (m_proxy) m_proxy->release();
m_proxy = new FarmControllerProxy(controller);
m_proxy->addRef();
return *this;
}
TFarmController *operator->() { return getPointer(); }
TFarmController *getPointer() const {
return m_proxy ? m_proxy->getController() : 0;
}
};
//==============================================================================
//==============================================================================
class FarmServer final : public TFarmExecutor, public TFarmServer {
public:
FarmServer(int port, TUserLog *log);
~FarmServer();
void setController(const ControllerData &data) {
m_controllerData = data;
TFarmController *controller = 0;
TFarmControllerFactory factory;
factory.create(data, &controller);
m_controller = controller;
}
TFarmController *getController() const { return m_controller.getPointer(); }
void setAppPaths(const std::vector<TFilePath> &);
QString execute(const std::vector<QString> &argv) override;
// TFarmServer overrides
int addTask(const QString &taskid, const QString &cmdline) override;
int terminateTask(const QString &taskid) override;
int getTasks(std::vector<QString> &tasks) override;
void queryHwInfo(HwInfo &hwInfo) override;
void attachController(const ControllerData &data);
void attachController(const QString &name, const QString &addr,
int port) override {
attachController(ControllerData(name, addr, port));
}
void detachController(const ControllerData &data);
void detachController(const QString &name, const QString &addr,
int port) override {
detachController(ControllerData(name, addr, port));
}
// class specific methods
void removeTask(const QString &id);
private:
TThread::Executor *m_executor;
ControllerData m_controllerData;
FarmControllerProxyP m_controller;
TThread::Mutex m_mux;
std::vector<QString> m_tasks;
TUserLog *m_userLog;
public:
// vector<TFilePath> m_appPaths;
private:
// not implemented
FarmServer(const FarmServer &);
FarmServer &operator=(const FarmServer &);
};
//===================================================================
//===================================================================
//
// class Task
//
//===================================================================
//===================================================================
class Task final : public TThread::Runnable {
public:
Task(const QString &id, const QString &cmdline, TUserLog *log,
FarmServer *server, const FarmControllerProxyP &controller)
: m_id(id)
, m_cmdline(cmdline)
, m_log(log)
, m_server(server)
, m_controller(controller) {}
void run() override;
private:
QString m_id;
QString m_cmdline;
TUserLog *m_log;
FarmServer *m_server;
FarmControllerProxyP m_controller;
private:
// not implemented
Task(const Task &);
Task &operator=(const Task &);
};
//-------------------------------------------------------------------
static QString getExeName(bool isComposer) {
QString name = isComposer ? "tcomposer" : "tcleanup";
#ifdef _WIN32
return name + ".exe ";
#elif defined(MACOSX)
TVER::ToonzVersion tver;
return "\"./" + QString::fromStdString(tver.getAppName()) +
".app/Contents/MacOS/" + name + "\" ";
#else
return name;
#endif
}
//------------------------------------------------------------------------------
void Task::run() {
QString cmdline;
// ===========
// remap commandLine to local executable
QStringList l = m_cmdline.split(" ");
QString appName = l.at(0);
// m_log->info(appName);
if (appName.contains("tcomposer") || appName.contains("tcleanup")) {
bool m_isComposerTask = appName.contains("tcomposer");
// m_log->info(QString::number(m_isComposerTask));
appName = getExeName(m_isComposerTask);
// m_log->info(appName);
int i = 0;
cmdline = appName;
// m_log->info(cmdline);
for (i = 1; i < l.size(); i++) {
cmdline += " ";
cmdline += l.at(i);
// m_log->info(cmdline);
}
// m_log->info("remap commandLine to local executable");
// m_log->info(appName);
} else {
cmdline = m_cmdline;
}
// ===========
QString logMsg("Starting task at ");
logMsg += QDateTime::currentDateTime().toString();
logMsg += "\n";
logMsg += "\"" + cmdline + "\"";
logMsg += "\n\n";
m_log->info(logMsg);
// ===========
#ifdef _WIN32
if (m_cmdline.contains("runcasm")) service.mountDisks();
#endif
if (m_cmdline.contains(".bat"))
cmdline = "cmd /C " + cmdline;
else
cmdline = cmdline;
#ifdef LEVO
else {
// metto da parte il primo token della command line che e' il nome
// dell'eseguibile
// Attenzione: case sensitive!
QStringList l = m_cmdline.split(" ");
// assert(!"CONTROLLARE QUI");
QString appName = l.at(1);
int i;
for (i = 2; i < l.size(); i++) cmdline += l.at(i);
// cerco se il nome dell'applicazione e' tra quelle del file di
// configurazione
for (auto const &appPath : m_server->m_appPaths) {
if (appPath.getName() == appName.toStdString()) {
exename = QString::fromStdWString(appPath.getWideString());
break;
}
}
}
#endif // LEVO
// cout << exename << endl;
// cout << cmdline << endl;
QProcess process;
process.start(cmdline);
process.waitForFinished(-1);
int exitCode = process.exitCode();
int errorCode = process.error();
bool ret = (errorCode != QProcess::UnknownError) || exitCode;
// int ret=QProcess::execute(/*"C:\\depot\\vincenzo\\toonz\\main\\x86_debug\\"
// +*/cmdline);
if (ret != 0) {
QString logMsg("Task aborted ");
logMsg += "\n\n";
m_log->warning(logMsg);
m_controller->taskSubmissionError(m_id, exitCode);
} else {
logMsg = "Task completed at ";
logMsg += QDateTime::currentDateTime().toString();
logMsg += "\n\n";
m_log->info(logMsg);
m_controller->taskCompleted(m_id, exitCode);
// CloseHandle(hJob);
}
m_server->removeTask(m_id);
//************* COMMENTATO A CAUSA DI UN PROBLEMA SU XP
// ora i dischi vengono montati al primo task di tipo "runcasm"
// e smontati allo stop del servizio
// service.unmountDisks();
}
//==============================================================================
//==============================================================================
FarmServer::FarmServer(int port, TUserLog *log)
: TFarmExecutor(port), m_controller(), m_userLog(log) {
TFarmServer::HwInfo hwInfo;
queryHwInfo(hwInfo);
m_executor = new TThread::Executor;
m_executor->setMaxActiveTasks(1);
}
//------------------------------------------------------------------------------
FarmServer::~FarmServer() { delete m_executor; }
//------------------------------------------------------------------------------
QString FarmServer::execute(const std::vector<QString> &argv) {
if (argv.size() > 0) {
if (argv[0] == "addTask" && argv.size() == 3) {
// assert(!"Da fare");
int ret = addTask(argv[1], argv[2]);
return QString::number(ret);
} else if (argv[0] == "terminateTask" && argv.size() > 1) {
int ret = terminateTask(argv[1]);
return QString::number(ret);
} else if (argv[0] == "getTasks") {
std::vector<QString> tasks;
int ret = getTasks(tasks);
QString reply(QString::number(ret));
reply += ",";
for (auto const &e : tasks) {
reply += e;
reply += ",";
}
if (!reply.isEmpty()) reply = reply.left(reply.size() - 1);
return reply;
} else if (argv[0] == "queryHwInfo") {
TFarmServer::HwInfo hwInfo;
queryHwInfo(hwInfo);
QString ret;
ret += QString::number((unsigned long)hwInfo.m_cpuCount);
ret += ",";
ret += QString::number((unsigned long)(hwInfo.m_totPhysMem / 1024));
ret += ",";
ret += QString::number((unsigned long)(hwInfo.m_availPhysMem / 1024));
ret += ",";
ret += QString::number((unsigned long)(hwInfo.m_totVirtMem / 1024));
ret += ",";
ret += QString::number((unsigned long)(hwInfo.m_availVirtMem / 1024));
ret += ",";
ret += QString::number(hwInfo.m_type);
return ret;
} else if (argv[0] == "attachController" && argv.size() > 3) {
int port;
fromStr(port, argv[3]);
attachController(ControllerData(argv[1], argv[2], port));
return "";
} else if (argv[0] == "detachController" && argv.size() > 3) {
int port;
fromStr(port, argv[3]);
detachController(ControllerData(argv[1], argv[2], port));
return "";
}
}
return QString::number(-1);
;
}
//------------------------------------------------------------------------------
int FarmServer::addTask(const QString &id, const QString &cmdline) {
// std::cout << "Server: addTask" << id << cmdline << std::endl;
QString lcmdline = cmdline;
if (lcmdline.contains("runcasm")) {
// il task e' runcasm
TFilePath rootDir = getGlobalRoot();
TFilePath logfilePath =
(rootDir + "logs" + id.toStdString()).withType(".log");
lcmdline +=
" -logfile " + QString::fromStdWString(logfilePath.getWideString());
TFilePath casmpmeterFp = getBinRoot() + CASMPMETER;
lcmdline += " -ac " + QString::fromStdWString(casmpmeterFp.getWideString());
lcmdline += " -ac_args " + QString(QUOTE_STR);
lcmdline += "$count $total $frame $filename " + id + QUOTE_STR;
}
if (lcmdline.contains("zrender")) lcmdline += " -taskid " + id;
if (lcmdline.contains("tcomposer")) {
lcmdline += " -farm " + QString::number(m_controllerData.m_port) + "@" +
m_controllerData.m_hostName;
lcmdline += " -id " + id;
}
m_executor->addTask(new Task(id, lcmdline, m_userLog, this, m_controller));
QMutexLocker sl(&m_mux);
m_tasks.push_back(id);
return 0;
}
//------------------------------------------------------------------------------
int FarmServer::terminateTask(const QString &taskid) {
#ifdef _WIN32
HANDLE hJob = OpenJobObject(MAXIMUM_ALLOWED, // access right
TRUE, // inheritance state
#if QT_VERSION >= 0x050500
taskid.toUtf8()); // job name
#else
taskid.toAscii()); // job name
#endif
if (hJob != NULL) {
BOOL res = TerminateJobObject(hJob, // handle to job
2); // exit code
}
#else
#endif
return 0;
}
//------------------------------------------------------------------------------
int FarmServer::getTasks(std::vector<QString> &tasks) {
QMutexLocker sl(&m_mux);
tasks = m_tasks;
return m_tasks.size();
}
//------------------------------------------------------------------------------
void FarmServer::queryHwInfo(HwInfo &hwInfo) {
#ifdef _WIN32
MEMORYSTATUS buff;
GlobalMemoryStatus(&buff);
hwInfo.m_totPhysMem = buff.dwTotalPhys;
hwInfo.m_availPhysMem = buff.dwAvailPhys;
hwInfo.m_totVirtMem = buff.dwTotalVirtual;
hwInfo.m_availVirtMem = buff.dwAvailVirtual;
hwInfo.m_cpuCount = TSystem::getProcessorCount();
hwInfo.m_type = Windows;
#else
// We can just retrieve the overall physical memory - the rest is defaulted to
// 500 MB
hwInfo.m_totPhysMem = TSystem::getMemorySize(true);
hwInfo.m_availPhysMem = TSystem::getFreeMemorySize(true);
hwInfo.m_totVirtMem = 500000000;
hwInfo.m_availVirtMem = 500000000;
hwInfo.m_cpuCount = TSystem::getProcessorCount();
#ifdef __sgi
hwInfo.m_type = Irix;
#else
hwInfo.m_type = Linux;
#endif
#endif
}
//------------------------------------------------------------------------------
void FarmServer::attachController(const ControllerData &data) {
setController(data);
}
//------------------------------------------------------------------------------
void FarmServer::detachController(const ControllerData &data) {
if (m_controllerData == data) {
// delete m_controller;
m_controller = 0;
}
}
//------------------------------------------------------------------------------
void FarmServer::removeTask(const QString &id) {
QMutexLocker sl(&m_mux);
std::vector<QString>::iterator it = find(m_tasks.begin(), m_tasks.end(), id);
if (it != m_tasks.end()) m_tasks.erase(it);
}
//==============================================================================
namespace {
std::string getLine(std::istream &is) {
std::string out;
char c;
while (!is.eof()) {
is.get(c);
if (c != '\r') {
if (c != '\n') {
if (!is.fail()) {
out.append(1, c);
} else {
break;
}
} else {
break;
}
}
}
return out;
}
} // anonymous namespace
int inline STRICMP(const QString &a, const QString &b) {
return a.compare(b, Qt::CaseSensitive);
}
int inline STRICMP(const char *a, const char *b) {
QString str(a);
return str.compare(QString(b), Qt::CaseSensitive);
}
static bool loadServerData(const QString &hostname, QString &addr, int &port) {
TFilePath rootDir = getGlobalRoot();
TFilePath fp = rootDir + "config" + "servers.txt";
#ifndef _WIN32
int acc = access(::to_string(fp).c_str(), 00); // 00 == solo esistenza
bool fileExists = acc != -1;
if (!fileExists) return false;
#endif
Tifstream is(fp);
if (!is.good()) return false;
while (!is.eof()) {
std::string line = getLine(is);
std::istringstream iss(line);
std::string name;
std::string ipAddress;
iss >> name >> ipAddress >> port;
if (name[0] == '#') continue;
#if QT_VERSION >= 0x050500
if (STRICMP(hostname.toUtf8(), name.c_str()) == 0)
#else
if (STRICMP(hostname.toAscii(), name.c_str()) == 0)
#endif
{
addr = QString(ipAddress.c_str());
return true;
}
}
return false;
}
//==============================================================================
void FarmServerService::onStart(int argc, char *argv[]) {
// Initialize thread components
TThread::init();
TVER::ToonzVersion tver;
#ifdef _WIN32
// DebugBreak();
#endif
TFilePath lRootDir = getLocalRoot();
TFileStatus fs(lRootDir);
bool lRootDirExists = fs.isDirectory();
if (!lRootDirExists) {
std::string errMsg("Unable to start the Server");
errMsg += "\n";
errMsg += "The directory " + ::to_string(lRootDir) +
" specified as Local Root does not exist";
errMsg += "\n";
addToMessageLog(errMsg);
// DEBUG MAC SERVIZIO (DA TOGLIERE)
#ifdef MACOSX
system("echo 'local root does not exist' >> err.log");
#endif
// exit the program
setStatus(TService::Stopped, NO_ERROR, 0);
}
TFilePath gRootDir = getGlobalRoot();
if (::to_string(gRootDir) == "") {
std::string errMsg("Unable to get TFARMGLOBALROOT environment variable (" +
::to_string(gRootDir) + ")");
addToMessageLog(errMsg);
// DEBUG MAC SERVIZIO (DA TOGLIERE)
#ifdef MACOSX
system("echo 'Unable to set the global root' >> err.log");
#endif
// exit the program
setStatus(TService::Stopped, NO_ERROR, 0);
}
bool gRootDirExists = dirExists(gRootDir);
;
if (!gRootDirExists) {
std::string errMsg("Unable to start the Server");
errMsg += "\n";
errMsg += "The directory " + ::to_string(gRootDir) +
" specified as Global Root does not exist";
;
addToMessageLog(errMsg);
// DEBUG MAC SERVIZIO (DA TOGLIERE)
#ifdef MACOSX
system("echo 'Global root does not exist' >> err.log");
#endif
// exit the program
setStatus(TService::Stopped, NO_ERROR, 0);
}
// legge dal file di configurazione le informazioni sul controller
TFilePath fp = gRootDir + "config" + "controller.txt";
ControllerData controllerData;
try {
::loadControllerData(fp, controllerData);
} catch (TException &e) {
std::string errMsg("Unable to start the Server");
errMsg += "\n";
errMsg += ::to_string(e.getMessage());
addToMessageLog(errMsg);
setStatus(TService::Stopped, NO_ERROR, 0); // exit the program
}
if (isRunningAsConsoleApp()) {
// i messaggi verranno ridiretti sullo standard output
m_userLog = new TUserLog();
} else {
TFilePath logFilePath = lRootDir + "server.log";
m_userLog = new TUserLog(logFilePath);
}
std::string appverinfo = tver.getAppVersionInfo("Farm Server") + "\n\n";
m_userLog->info(appverinfo.c_str());
// legge dal file di configurazione dei server il numero di porta da
// utilizzare
bool ret = loadServerData(TSystem::getHostName(), m_addr, m_port);
if (!ret) {
QString msg("Unable to get the port number of ");
msg += TSystem::getHostName();
msg += " from the servers config file";
msg += "\n";
msg += "Using the default port number ";
msg += QString::number(m_port);
msg += "\n";
msg += "\n";
m_userLog->info(msg);
m_port = 8002;
}
#ifdef __sgi
{
std::ofstream os("/tmp/.tfarmserverd.dat");
os << m_port;
}
#endif
m_farmServer = new FarmServer(m_port, m_userLog);
m_farmServer->setController(controllerData);
try {
m_farmServer->getController()->attachServer(TSystem::getHostName(), m_addr,
m_port);
} catch (TException const &) {
}
#ifdef _WIN32
TFilePath diskMountingsFilePath = lRootDir + "config" + "diskmap.cfg";
if (myDoesExists(diskMountingsFilePath)) {
loadDiskMountingPoints(diskMountingsFilePath);
// i dischi vengono montati al primo task di tipo "runcasm"
// e smontati allo stop del servizio
// mountDisks();
}
#endif
// Carica da un file di configurazione i path dei programmi da lanciare.
// Per tutti i programmi il cui path non e' contenuto nel file di
// configurazione
// si assume che il path del folder del programma sia specificato
// nella variabile di sistema PATH
QEventLoop eventLoop;
// Connect the server's listening finished signal to main loop quit.
QObject::connect(m_farmServer, SIGNAL(finished()), &eventLoop, SLOT(quit()));
// Run the TcpIp server's listening state
m_farmServer->start();
// Main loop starts here
eventLoop.exec();
//----------------------Farm server loops here------------------------
int rc = m_farmServer->getExitCode();
#ifdef __sgi
remove("/tmp/.tfarmserver.dat");
#endif
if (rc != 0) {
std::string msg("An error occurred starting the ToonzFarm Server");
msg += "\n";
#ifdef _WIN32
LPVOID lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, rc,
0, // Default language
(LPTSTR)&lpMsgBuf, 0, NULL);
msg += std::string((char *)lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
#else
#endif
addToMessageLog(msg);
m_userLog->error(QString::fromStdString(msg));
setStatus(TService::Stopped, NO_ERROR, 0);
}
std::string msg("Exiting with code ");
msg += std::to_string(ret);
msg += "\n";
m_userLog->info(QString::fromStdString(msg));
}
//------------------------------------------------------------------------------
void FarmServerService::onStop() {
try {
m_farmServer->getController()->detachServer(TSystem::getHostName(), m_addr,
m_port);
} catch (TException & /*e*/) {
}
// i dischi vengono montati al primo task di tipo "runcasm"
// e smontati allo stop del servizio
#ifdef _WIN32
unmountDisks();
#endif
TTcpIpClient client;
int socketId;
int ret = client.connect(TSystem::getHostName(), "", m_farmServer->getPort(),
socketId);
if (ret == OK) {
client.send(socketId, "shutdown");
}
}
#ifdef _WIN32
//------------------------------------------------------------------------------
void FarmServerService::loadDiskMountingPoints(const TFilePath &fp) {
Tifstream is(fp);
if (!is) throw std::string("File " + ::to_string(fp) + " not found");
char buffer[1024];
while (is.getline(buffer, sizeof(buffer))) {
char *s = buffer;
while (isBlank(*s)) s++;
if (*s == '\0' || *s == '#' || *s == '!') continue;
if (*s == '=') continue; // errore: from vuoto
char *t = s;
while (*t && *t != '=') t++;
if (*t != '=') continue; // errore: manca '='
char *q = t;
while (q > s && isBlank(*(q - 1))) q--;
if (q == s)
continue; // non dovrebbe succedere mai: prima di '=' tutti blanks
std::string from(s, q - s);
s = t + 1;
while (isBlank(*s)) s++;
if (*s == '\0') continue; // errore: dst vuoto
t = s;
while (*t) t++;
while (t > s && isBlank(*(t - 1))) t--;
if (t == s) continue; // non dovrebbe succedere mai: dst vuoto
std::string dst(s, t - s);
m_disks[from] = dst;
}
}
//------------------------------------------------------------------------------
void FarmServerService::mountDisks() {
std::map<std::string, std::string>::iterator it = m_disks.begin();
for (; it != m_disks.end(); ++it) {
std::string drive = it->first;
std::string remoteName = it->second;
NETRESOURCE NetResource;
NetResource.dwType = RESOURCETYPE_DISK;
NetResource.lpLocalName = (LPSTR)drive.c_str(); // "O:";
NetResource.lpRemoteName =
(LPSTR)remoteName.c_str(); // "\\\\vega\\PERSONALI";
NetResource.lpProvider = NULL;
DWORD res =
WNetAddConnection2(&NetResource, // connection details
0, // password
#if QT_VERSION >= 0x050500
TSystem::getUserName().toUtf8(), // user name
#else
TSystem::getUserName().toAscii(), // user name
#endif
0); // connection options
if (res == NO_ERROR) m_disksMounted.push_back(drive);
if (res != NO_ERROR && res != ERROR_ALREADY_ASSIGNED) {
// ERROR_BAD_NET_NAME
DWORD dwLastError;
char errorBuf[1024];
char nameBuf[1024];
DWORD rett =
WNetGetLastError(&dwLastError, // error code
errorBuf, // error description buffer
sizeof(errorBuf), // size of description buffer
nameBuf, // buffer for provider name
sizeof(nameBuf)); // size of provider name buffer
std::string errorMessage("Unable to map ");
errorMessage += NetResource.lpRemoteName;
errorMessage += " to logic volume ";
errorMessage += NetResource.lpLocalName;
addToMessageLog(errorMessage);
}
}
}
//------------------------------------------------------------------------------
void FarmServerService::unmountDisks() {
for (auto const &drive : m_disksMounted) {
DWORD res =
WNetCancelConnection2(drive.c_str(), // resource name
CONNECT_UPDATE_PROFILE, // connection type
TRUE); // unconditional disconnect option
if (res != NO_ERROR && res != ERROR_NOT_CONNECTED) {
std::string errorMessage("Unable to unmap ");
errorMessage += drive.c_str();
addToMessageLog(errorMessage);
}
}
m_disksMounted.clear();
}
#endif
//==============================================================================
//==============================================================================
//==============================================================================
int main(int argc, char **argv) {
QCoreApplication a(argc, argv);
bool console = false;
if (argc > 1) {
std::string serviceName(
"ToonzFarmServer"); // Must be the same of the installer's
std::string serviceDisplayName = serviceName;
TCli::SimpleQualifier consoleQualifier("-console", "Run as console app");
TCli::StringQualifier installQualifier("-install name",
"Install service as 'name'");
TCli::SimpleQualifier removeQualifier("-remove", "Remove service");
TCli::Usage usage(argv[0]);
usage.add(consoleQualifier + installQualifier + removeQualifier);
if (!usage.parse(argc, argv)) exit(1);
#ifdef _WIN32
if (installQualifier.isSelected()) {
char szPath[512];
if (installQualifier.getValue() != "")
serviceDisplayName = installQualifier.getValue();
if (GetModuleFileName(NULL, szPath, 512) == 0) {
std::cout << "Unable to install";
std::cout << serviceName << " - ";
std::cout << getLastErrorText().c_str() << std::endl << std::endl;
return 0;
}
TService::install(serviceName, serviceDisplayName, TFilePath(szPath));
return 0;
}
if (removeQualifier.isSelected()) {
TService::remove(serviceName);
return 0;
}
#endif
if (consoleQualifier.isSelected()) console = true;
}
TSystem::hasMainLoop(false);
TService::instance()->run(argc, argv, console);
return 0;
}