summaryrefslogtreecommitdiffstats
path: root/ProcessManager.cpp
diff options
context:
space:
mode:
authorMarkus Mittendrein <git@maxmitti.tk>2015-03-18 17:38:51 +0100
committerMarkus Mittendrein <git@maxmitti.tk>2015-03-18 17:38:51 +0100
commit8983d3b38421843db67a05edee180028959c1b51 (patch)
tree904305965e9ba3baa27680d5d8b2a7b8dbea213e /ProcessManager.cpp
parentfbe3c5fbe1327fd81e2eb8fe30a75c4cf5d7b35c (diff)
downloadmanager-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.cpp245
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;
+}
+