diff --git a/CMakeLists.txt b/CMakeLists.txt index c83979b..d25973c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.5) -project(smsub LANGUAGES CXX) +project(smsub LANGUAGES CXX VERSION 0.7) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/SMSubProcess.cpp b/SMSubProcess.cpp index 7ee45cc..14ef091 100644 --- a/SMSubProcess.cpp +++ b/SMSubProcess.cpp @@ -22,8 +22,8 @@ #include "smsub.h" #include -SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout) : - termTimeout(termTimeout) +SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout, const bool &keepAlive) : + termTimeout(termTimeout), keepAlive(keepAlive) { // Set process executable, arguments and working directory process.setProgram(executable); @@ -41,26 +41,31 @@ SMSubProcess::SMSubProcess(const QString &executable, const QStringList &argumen QObject::connect(&process, &QProcess::errorOccurred, this, &SMSubProcess::processError); QObject::connect(&process, &QProcess::started, this, [=]() { QTextStream(stderr) << "Subprocess started!" << smsub_endl; + emit statusUpdated(true); }); QObject::connect(&process, QOverload::of(&QProcess::finished), this, [=](int exitCode) { QTextStream(stderr) << "Subprocess exited!" << smsub_endl; // Exit with the same exit code as the process - emit processStopped(); - QCoreApplication::exit(exitCode); + emit statusUpdated(false); + if (!keepAlive) + QCoreApplication::exit(exitCode); }); } -void SMSubProcess::start() -{ - process.start(QIODevice::ReadWrite); -} - void SMSubProcess::readyRead() { #ifdef SMSUB_IODEBUG QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl; #endif // Read process output and emit event +#ifdef SMSUB_BUFFERED_READS +#ifdef SMSUB_IODEBUG + QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl; +#endif + const QByteArray readData = process.read(1024); + if (!readData.isEmpty()) + emit outputWritten(readData); +#else while (process.canReadLine()) { #ifdef SMSUB_IODEBUG QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl; @@ -68,6 +73,7 @@ void SMSubProcess::readyRead() const QByteArray readData = process.readLine().trimmed(); emit outputWritten(readData + '\n'); } +#endif } void SMSubProcess::processError(QProcess::ProcessError error) @@ -75,11 +81,13 @@ void SMSubProcess::processError(QProcess::ProcessError error) // Handle process errors if (Q_LIKELY(error == QProcess::FailedToStart)) { QTextStream(stderr) << "Process failed to start!" << smsub_endl; - QCoreApplication::exit(1); + if (!keepAlive) + QCoreApplication::exit(1); } else if (error == QProcess::UnknownError) { QTextStream(stderr) << "Unknown error occurred!" << smsub_endl; - QCoreApplication::exit(1); + if (!keepAlive) + QCoreApplication::exit(1); } } @@ -94,20 +102,25 @@ void SMSubProcess::aboutToQuit() } } -void SMSubProcess::killProcess() +void SMSubProcess::startProcess() { - // Kill process as requested - if (process.state() == QProcess::Running) { - process.kill(); - } + // Start process as requested + if (process.state() == QProcess::NotRunning) + process.start(QIODevice::ReadWrite); } void SMSubProcess::stopProcess() { // Terminate process as requested - if (process.state() == QProcess::Running) { + if (process.state() == QProcess::Running) process.terminate(); - } +} + +void SMSubProcess::killProcess() +{ + // Kill process as requested + if (process.state() == QProcess::Running) + process.kill(); } void SMSubProcess::writeInput(const QByteArray &input) @@ -116,5 +129,6 @@ void SMSubProcess::writeInput(const QByteArray &input) QTextStream(stderr) << "Subprocess I/O IN!" << smsub_endl; #endif // Write input from Unix/IPC socket to process - process.write(input); + if (process.state() == QProcess::Running) + process.write(input); } diff --git a/SMSubProcess.h b/SMSubProcess.h index 5f36a0f..cd2dddc 100644 --- a/SMSubProcess.h +++ b/SMSubProcess.h @@ -26,17 +26,18 @@ class SMSubProcess : public QObject { Q_OBJECT public: - SMSubProcess(const QString &executable, const QStringList &arguments, const QString& workingDirectory, const int &termTimeout = 60000); - void start(); + SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout = 60000, const bool &keepAlive = false); private: QProcess process; int termTimeout; + bool keepAlive; public slots: void aboutToQuit(); - void killProcess(); + void startProcess(); void stopProcess(); + void killProcess(); void writeInput(const QByteArray &input); private slots: @@ -45,8 +46,7 @@ private slots: signals: void outputWritten(const QByteArray &output); - void processStopped(); - + void statusUpdated(const bool status); }; #endif // SMSUBPROCESS_H diff --git a/SMSubServer.cpp b/SMSubServer.cpp index dd92038..c753b79 100644 --- a/SMSubServer.cpp +++ b/SMSubServer.cpp @@ -32,6 +32,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &soc type = ServerType::Local; server = localServer; + status = false; } SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &serverName, const quint16 &port) : serverSettings(serverSettings) @@ -43,6 +44,7 @@ SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &ser type = ServerType::WebSocket; server = webSocketServer; + status = false; } bool SMSubServer::isListening() @@ -122,14 +124,30 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message) sendMessage(socket, "Permission denied!\n"); } } - else if (message.startsWith("kill")) { - emit killRequested(); - debugOutput(socket, "Killing server!"); + else if (message.startsWith("status")) { + if (status) { + sendMessage(socket, "Status: on\n"); + } + else { + sendMessage(socket, "Status: off\n"); + } + } + else if (message.startsWith("start")) { + emit startRequested(); + debugOutput(socket, "Starting server!"); } else if (message.startsWith("stop")) { emit stopRequested(); debugOutput(socket, "Stopping server!"); } + else if (message.startsWith("kill")) { + emit killRequested(); + debugOutput(socket, "Killing server!"); + } + else if (message.startsWith("quit")) { + QTimer::singleShot(0, qApp, &QCoreApplication::quit); + debugOutput(socket, "Qutting smsub!"); + } else if (message.startsWith("wl")) { const QByteArray writeData = message.mid(3); emit inputWritten(writeData + '\n'); @@ -254,3 +272,8 @@ void SMSubServer::registerToken(const QString &token) tokens.removeAll(token); }); } + +void SMSubServer::statusUpdated(const bool status_) +{ + status = status_; +} diff --git a/SMSubServer.h b/SMSubServer.h index 29de80a..daabb22 100644 --- a/SMSubServer.h +++ b/SMSubServer.h @@ -45,6 +45,7 @@ public: public slots: void writeOutput(const QByteArray &output); void registerToken(const QString &token); + void statusUpdated(const bool status); private slots: void wsMessageReceived(const QByteArray &message); @@ -61,12 +62,14 @@ private: QVector tokens; ServerType type; QObject *server; + bool status; signals: void tokenRegistered(const QString &password); void inputWritten(const QByteArray &input); - void killRequested(); + void startRequested(); void stopRequested(); + void killRequested(); }; #endif // SMSUBSERVER_H diff --git a/main.cpp b/main.cpp index 8575ff7..aebda4d 100644 --- a/main.cpp +++ b/main.cpp @@ -134,13 +134,14 @@ int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setApplicationName("Server Manager Subprocess"); - a.setApplicationVersion("0.6"); + a.setApplicationVersion("0.7"); #ifdef Q_OS_UNIX catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM}); #endif bool rportSet = false; + bool keepAlive = false; bool timeoutSet = false; int termTimeout = 60000; quint16 rport; @@ -151,6 +152,7 @@ int main(int argc, char *argv[]) QStringList argumentList; const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE"); + const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE"); const QByteArray envManifest = qgetenv("SMSUB_JSON"); const QByteArray envExecutable = qgetenv("SMSUB_EXEC"); const QByteArray envArguments = qgetenv("SMSUB_ARGS"); @@ -160,7 +162,7 @@ int main(int argc, char *argv[]) const QByteArray envTimeout = qgetenv("SMSUB_TIMEOUT"); const QByteArray envWorkDir = qgetenv("SMSUB_WORKDIR"); - if (envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true") { + if (envEnvironmentMode == "1" || envEnvironmentMode.toLower() == "true" || envEnvironmentMode.toLower() == "yes") { if (envExecutable.isEmpty() && envArguments.isEmpty()) { QStringList arguments = a.arguments(); arguments.removeFirst(); @@ -202,6 +204,12 @@ int main(int argc, char *argv[]) } } + if (!envKeepAlive.isEmpty()) { + if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") { + keepAlive = true; + } + } + if (!envWorkDir.isEmpty()) { workingDirectory = QString::fromUtf8(envWorkDir); } @@ -334,6 +342,12 @@ int main(int argc, char *argv[]) executable = QString::fromUtf8(envExecutable); } + if (!envKeepAlive.isEmpty()) { + if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") { + keepAlive = true; + } + } + if (!envWorkDir.isEmpty()) { workingDirectory = QString::fromUtf8(envWorkDir); } @@ -371,6 +385,16 @@ int main(int argc, char *argv[]) return 1; } + if (jsonObject.contains("KeepAlive")) { + const QJsonValue jsonKeepAlive = jsonObject.value("KeepAlive"); + if (!jsonKeepAlive.isBool()) { + QTextStream(stderr) << "KeepAlive is not a bool in manifest, aborting!" << smsub_endl; + manifestFile.close(); + return 1; + } + keepAlive = jsonKeepAlive.toBool(); + } + if (jsonObject.contains("WorkingDirectory")) { const QJsonValue jsonWorkingDirectory = jsonObject.value("WorkingDirectory"); if (!jsonWorkingDirectory.isString()) { @@ -486,7 +510,7 @@ int main(int argc, char *argv[]) return 1; } - SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout); + SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, keepAlive); SMSubServerSettings remoteSettings; remoteSettings.canRegister = false; @@ -505,9 +529,11 @@ int main(int argc, char *argv[]) localSettings.canRegister = true; QObject::connect(&subLocal, &SMSubServer::tokenRegistered, subRemote, &SMSubServer::registerToken); QObject::connect(&subProcess, &SMSubProcess::outputWritten, subRemote, &SMSubServer::writeOutput); + QObject::connect(&subProcess, &SMSubProcess::statusUpdated, subRemote, &SMSubServer::statusUpdated); QObject::connect(subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); - QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(subRemote, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess); QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); + QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); } else if (rportSet) { SMSubServer *subRemote = new SMSubServer(&remoteSettings, QString(), rport); @@ -518,21 +544,25 @@ int main(int argc, char *argv[]) localSettings.canRegister = true; QObject::connect(&subLocal, &SMSubServer::tokenRegistered, subRemote, &SMSubServer::registerToken); QObject::connect(&subProcess, &SMSubProcess::outputWritten, subRemote, &SMSubServer::writeOutput); + QObject::connect(&subProcess, &SMSubProcess::statusUpdated, subRemote, &SMSubServer::statusUpdated); QObject::connect(subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); - QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(subRemote, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess); QObject::connect(subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); + QObject::connect(subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); } else { localSettings.canRegister = false; } QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput); + QObject::connect(&subProcess, &SMSubProcess::statusUpdated, &subLocal, &SMSubServer::statusUpdated); QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); - QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(&subLocal, &SMSubServer::startRequested, &subProcess, &SMSubProcess::startProcess); QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); + QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); QObject::connect(&a, &QCoreApplication::aboutToQuit, &subProcess, &SMSubProcess::aboutToQuit); - subProcess.start(); + subProcess.startProcess(); QTextStream(stderr) << QString("SMSub Version %1 initialized!").arg(QCoreApplication::applicationVersion()) << smsub_endl;