| |
| #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 |
| |
| |
| |
| #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 |
| |
| std::string unixpath = |
| "./" + tver.getAppName() + ".app/Contents/Resources/configfarmroot.txt"; |
| #else |
| |
| #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); |
| 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); |
| exists = acc != -1; |
| #endif |
| return exists; |
| } |
| |
| |
| |
| inline bool isBlank(char c) { return c == ' ' || c == '\t' || c == '\n'; } |
| |
| } |
| |
| |
| |
| |
| 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: |
| |
| FarmControllerProxy(const FarmControllerProxy &); |
| FarmControllerProxy &operator=(const FarmControllerProxy &); |
| }; |
| |
| |
| |
| 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; |
| |
| |
| 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)); |
| } |
| |
| |
| 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: |
| |
| |
| private: |
| |
| FarmServer(const FarmServer &); |
| FarmServer &operator=(const FarmServer &); |
| }; |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| 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: |
| |
| 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; |
| |
| |
| |
| |
| QStringList l = m_cmdline.split(" "); |
| QString appName = l.at(0); |
| |
| if (appName.contains("tcomposer") || appName.contains("tcleanup")) { |
| bool m_isComposerTask = appName.contains("tcomposer"); |
| |
| appName = getExeName(m_isComposerTask); |
| |
| |
| int i = 0; |
| cmdline = appName; |
| |
| for (i = 1; i < l.size(); i++) { |
| cmdline += " "; |
| cmdline += l.at(i); |
| |
| } |
| |
| |
| } 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 { |
| |
| |
| |
| QStringList l = m_cmdline.split(" "); |
| |
| QString appName = l.at(1); |
| int i; |
| for (i = 2; i < l.size(); i++) cmdline += l.at(i); |
| |
| |
| |
| for (auto const &appPath : m_server->m_appPaths) { |
| if (appPath.getName() == appName.toStdString()) { |
| exename = QString::fromStdWString(appPath.getWideString()); |
| break; |
| } |
| } |
| } |
| #endif // LEVO |
| |
| |
| |
| |
| |
| QString prgName; |
| QString argsStr = ""; |
| int sepPos = cmdline.indexOf(" "); |
| |
| if (sepPos == -1) { |
| prgName = cmdline; |
| } else { |
| prgName = cmdline.left(sepPos); |
| argsStr = cmdline.right(cmdline.size() - sepPos - 1); |
| } |
| |
| QProcess process; |
| process.setProgram(prgName); |
| #if defined(_WIN32) |
| process.setNativeArguments(argsStr); |
| #else |
| #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) |
| process.setArguments(argsStr.split(" ", Qt::SkipEmptyParts)); |
| #else |
| process.setArguments(argsStr.split(" ", QString::SkipEmptyParts)); |
| #endif |
| #endif |
| process.start(); |
| process.waitForFinished(-1); |
| |
| int exitCode = process.exitCode(); |
| int errorCode = process.error(); |
| bool ret = (errorCode != QProcess::UnknownError) || exitCode; |
| |
| |
| |
| |
| 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); |
| |
| |
| } |
| |
| m_server->removeTask(m_id); |
| |
| |
| |
| |
| |
| } |
| |
| |
| |
| |
| 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) { |
| |
| 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) { |
| |
| |
| QString lcmdline = cmdline; |
| |
| if (lcmdline.contains("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, |
| TRUE, |
| taskid.toUtf8()); |
| |
| if (hJob != NULL) { |
| BOOL res = TerminateJobObject(hJob, |
| 2); |
| } |
| #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 |
| |
| |
| 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) { |
| |
| 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; |
| } |
| |
| } |
| |
| 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); |
| 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 (STRICMP(hostname.toUtf8(), name.c_str()) == 0) { |
| addr = QString(ipAddress.c_str()); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| |
| void FarmServerService::onStart(int argc, char *argv[]) { |
| |
| TThread::init(); |
| TVER::ToonzVersion tver; |
| |
| #ifdef _WIN32 |
| |
| #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); |
| |
| |
| #ifdef MACOSX |
| system("echo 'local root does not exist' >> err.log"); |
| #endif |
| |
| |
| 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); |
| |
| |
| #ifdef MACOSX |
| system("echo 'Unable to set the global root' >> err.log"); |
| #endif |
| |
| |
| 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); |
| |
| |
| #ifdef MACOSX |
| system("echo 'Global root does not exist' >> err.log"); |
| #endif |
| |
| |
| setStatus(TService::Stopped, NO_ERROR, 0); |
| } |
| |
| |
| |
| 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); |
| } |
| |
| if (isRunningAsConsoleApp()) { |
| |
| 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()); |
| |
| |
| |
| |
| 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); |
| |
| |
| |
| |
| |
| } |
| #endif |
| |
| |
| |
| |
| |
| |
| |
| QEventLoop eventLoop; |
| |
| |
| QObject::connect(m_farmServer, SIGNAL(finished()), &eventLoop, SLOT(quit())); |
| |
| |
| m_farmServer->start(); |
| |
| |
| eventLoop.exec(); |
| |
| |
| |
| 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, |
| (LPTSTR)&lpMsgBuf, 0, NULL); |
| |
| msg += std::string((char *)lpMsgBuf); |
| |
| |
| 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 & ) { |
| } |
| |
| |
| |
| |
| #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; |
| char *t = s; |
| while (*t && *t != '=') t++; |
| if (*t != '=') continue; |
| char *q = t; |
| while (q > s && isBlank(*(q - 1))) q--; |
| if (q == s) |
| continue; |
| std::string from(s, q - s); |
| s = t + 1; |
| while (isBlank(*s)) s++; |
| if (*s == '\0') continue; |
| t = s; |
| while (*t) t++; |
| while (t > s && isBlank(*(t - 1))) t--; |
| if (t == s) continue; |
| 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(); |
| NetResource.lpRemoteName = |
| (LPSTR)remoteName.c_str(); |
| NetResource.lpProvider = NULL; |
| |
| DWORD res = |
| WNetAddConnection2(&NetResource, |
| 0, |
| TSystem::getUserName().toUtf8(), |
| 0); |
| |
| if (res == NO_ERROR) m_disksMounted.push_back(drive); |
| |
| if (res != NO_ERROR && res != ERROR_ALREADY_ASSIGNED) { |
| |
| |
| DWORD dwLastError; |
| char errorBuf[1024]; |
| char nameBuf[1024]; |
| |
| DWORD rett = |
| WNetGetLastError(&dwLastError, |
| errorBuf, |
| sizeof(errorBuf), |
| nameBuf, |
| sizeof(nameBuf)); |
| |
| 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(), |
| CONNECT_UPDATE_PROFILE, |
| TRUE); |
| |
| 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"); |
| 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; |
| } |