diff options
| author | Markus Mittendrein <git@maxmitti.tk> | 2015-03-18 17:38:51 +0100 |
|---|---|---|
| committer | Markus Mittendrein <git@maxmitti.tk> | 2015-03-18 17:38:51 +0100 |
| commit | 8983d3b38421843db67a05edee180028959c1b51 (patch) | |
| tree | 904305965e9ba3baa27680d5d8b2a7b8dbea213e /ProcessManager.cpp | |
| parent | fbe3c5fbe1327fd81e2eb8fe30a75c4cf5d7b35c (diff) | |
| download | manager-8983d3b38421843db67a05edee180028959c1b51.tar.gz manager-8983d3b38421843db67a05edee180028959c1b51.zip | |
Added ProcessManager, so Clonk can run independently from CRSM.
Added support for league with --league flag for !host.
Diffstat (limited to 'ProcessManager.cpp')
| -rw-r--r-- | ProcessManager.cpp | 245 |
1 files changed, 245 insertions, 0 deletions
diff --git a/ProcessManager.cpp b/ProcessManager.cpp new file mode 100644 index 0000000..6d2efe8 --- /dev/null +++ b/ProcessManager.cpp @@ -0,0 +1,245 @@ +#include "ProcessManager.hpp" + +#include <QProcess> +#include <QDebug> + +ProcessManager::ProcessManager(const QString &newPrefix, const QString &newId, bool useStdErr, QObject *parent) : QObject(parent), prefix(newPrefix), id(newId), useStdErr(useStdErr) +{ + if(id.isEmpty()) + { + id = QString::number(qrand()) + "-"; + } + stdIn.setFileName(prefix + id + "stdin"); + stdOut.setFileName(prefix + id + "stdout"); + stdErr.setFileName(prefix + id + "stderr"); + ctrlIn.setFileName(prefix + id + "ctrlin"); + ctrlOut.setFileName(prefix + id + "ctrlout"); + bool reattaching = false; + if(!ctrlIn.exists()) + { + if(!QProcess::startDetached("ProcessManager", QStringList() << prefix + id)) + { + return; + } + qDebug() << "Started new ProcessManager"; + qDebug() << "Waiting for ctrl-files"; + while(!ctrlIn.exists() || !ctrlOut.exists()); + } + else + { + qDebug() << "Reattaching"; + reattaching = true; + } + if(!ctrlIn.open(QFile::WriteOnly | QFile::Unbuffered)) + { + qDebug() << "ctrlin not open" << ctrlIn.errorString(); + return; + } + qDebug() << "Opened ctrlin"; + ctrlIn.write("HELLO\n"); + if(!ctrlOut.open(QFile::ReadOnly)) + { + qDebug() << "ctrlout not open" << ctrlOut.errorString(); + return; + } + qDebug() << "Opened ctrlout"; + if(ctrlOut.readLine() != "HELLO\n") + { + qDebug() << "not HELLO"; + return; + } + qDebug() << "HELLO"; + ctrlOutNotifier = new QSocketNotifier(ctrlOut.handle(), QSocketNotifier::Read, this); + connect(ctrlOutNotifier, SIGNAL(activated(int)), this, SLOT(ctrlOutReadyRead())); + ok = true; + if(reattaching) + { + ctrlIn.write("STATUS\n"); + QByteArray status = ctrlOut.readLine(); + if(status != "NOTRUNNING\n") + { + QRegExp runningExp("^RUNNING: (\\d+)\n$"); + if(runningExp.exactMatch(QString::fromUtf8(status))) + { + pid = runningExp.cap(1).toInt(); + running = connectToIO(); + } + } + } +} + +ProcessManager::~ProcessManager() +{ + +} + +bool ProcessManager::isOk() +{ + return ok; +} + +bool ProcessManager::isRunning() +{ + return ok && running; +} + +bool ProcessManager::start(const QString &program, QStringList args) +{ + if(!ok || running) + { + return false; + } + for(int i = 0; i < args.length(); ++i) + { + args[i] = args[i].replace('\\', "\\\\").replace(' ', "\\ "); + } + ctrlIn.write("START " + program.toUtf8() + " " + args.join(' ').toUtf8() + "\n"); + QRegExp runningExp("^RUNNING: (\\d+)\n$"); + if(!runningExp.exactMatch(ctrlOut.readLine())) + { + return false; + } + else + { + pid = runningExp.cap(1).toInt(); + return running = connectToIO(); + } +} + +QByteArray ProcessManager::readAll() +{ + return stdOut.readAll(); +} + +QByteArray ProcessManager::readLine() +{ + return stdOut.readLine(); +} + +qint64 ProcessManager::write(const QByteArray &data) +{ + if(stdIn.isWritable()) + { + return stdIn.write(data); + } + else + { + return -1; + } +} + +bool ProcessManager::isWritable() +{ + return ok && running && stdIn.isOpen() && stdIn.isWritable(); +} + +bool ProcessManager::setWorkingDirectory(const QString &path) +{ + if(!ok || !ctrlIn.isWritable() || running) + { + return false; + } + ctrlIn.write("CD " + path.toUtf8() + "\n"); + if(ctrlOut.readLine() != "CHANGED\n") + { + return false; + } + else + { + return true; + } +} + +void ProcessManager::kill() +{ + if(ok && running && ctrlIn.isWritable()) + { + ctrlIn.write("KILL\n"); + } +} + +void ProcessManager::exit() +{ + ctrlIn.write("EXIT\n"); +} + +void ProcessManager::closeProgFifos() +{ + ctrlIn.write("CLOSE\n"); + stdIn.close(); + stdOut.close(); + stdErr.close(); + DELETE_SAVE(stdOutNotifier); + DELETE_SAVE(stdErrNotifier); +} + +QString ProcessManager::ID() +{ + return id; +} + +void ProcessManager::ctrlOutReadyRead() +{ + QString what = QString::fromUtf8(ctrlOut.readLine()); + QRegExp quitExp("^QUIT: (\\d+)\n"); + if(quitExp.exactMatch(what)) + { + exitCode = quitExp.cap(1).toInt(); + running = false; + stdOut.close(); + stdErr.close(); + stdIn.close(); + DELETE_SAVE(stdOutNotifier); + DELETE_SAVE(stdErrNotifier); + emit finished(exitCode); + } +} + +void ProcessManager::_stdOutReadyRead() +{ + if(!stdOut.isOpen()) + { + DELETE_SAVE(stdOutNotifier); + } + emit readyRead(); +} + +void ProcessManager::_stdErrReadyRead() +{ + if(!stdErr.isOpen()) + { + DELETE_SAVE(stdErrNotifier); + } + emit stdErrReadyRead(); +} + +bool ProcessManager::connectToIO() +{ + if(!stdOut.open(QFile::ReadOnly)) + { + qDebug() << "stdout not open" << stdOut.errorString(); + return false; + } + qDebug() << "Opened stdout"; + if(!stdErr.open(QFile::ReadOnly)) + { + qDebug() << "stderr not open" << stdOut.errorString(); + return false; + } + qDebug() << "Opened stderr"; + if(!stdIn.open(QFile::WriteOnly | QFile::Unbuffered)) + { + qDebug() << "stdin not open" << stdOut.errorString(); + return false; + } + qDebug() << "Opened stdin"; + stdOutNotifier = new QSocketNotifier(stdOut.handle(), QSocketNotifier::Read, this); + connect(stdOutNotifier, SIGNAL(activated(int)), this, SLOT(_stdOutReadyRead())); + if(useStdErr) + { + stdErrNotifier = new QSocketNotifier(stdErr.handle(), QSocketNotifier::Read, this); + connect(stdErrNotifier, SIGNAL(activated(int)), this, SLOT(_stdErrReadyRead())); + } + return true; +} + |
