add BufferedReads, add AutoStart and KeepAlive command line options

This commit is contained in:
Syping 2024-05-07 17:29:23 +02:00
parent d37369ad4f
commit 1ddc4ff755
5 changed files with 78 additions and 41 deletions

View file

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
project(smsub LANGUAGES CXX VERSION 0.8) project(smsub LANGUAGES CXX VERSION 0.9)
set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_INCLUDE_CURRENT_DIR ON)

View file

@ -22,8 +22,8 @@
#include "SMSubProcess.h" #include "SMSubProcess.h"
#include "smsub.h" #include "smsub.h"
SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout, const bool &keepAlive) : SMSubProcess::SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int termTimeout, const bool buffReads, const bool keepAlive) :
termTimeout(termTimeout), keepAlive(keepAlive) termTimeout(termTimeout), buffReads(buffReads), keepAlive(keepAlive)
{ {
// Set process executable, arguments and working directory // Set process executable, arguments and working directory
process.setProgram(executable); process.setProgram(executable);
@ -33,7 +33,7 @@ SMSubProcess::SMSubProcess(const QString &executable, const QStringList &argumen
// manage input channel // manage input channel
process.setInputChannelMode(QProcess::ManagedInputChannel); process.setInputChannelMode(QProcess::ManagedInputChannel);
// stdout and stderr in same IO stream // stdout and stderr in same I/O stream
process.setProcessChannelMode(QProcess::MergedChannels); process.setProcessChannelMode(QProcess::MergedChannels);
// Connect process signal handlers // Connect process signal handlers
@ -58,14 +58,17 @@ void SMSubProcess::readyRead()
QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl; QTextStream(stderr) << "Subprocess I/O RR!" << smsub_endl;
#endif #endif
// Read process output and emit event // Read process output and emit event
#ifdef SMSUB_BUFFERED_READS if (buffReads) {
while (process.bytesAvailable()) {
#ifdef SMSUB_IODEBUG #ifdef SMSUB_IODEBUG
QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl; QTextStream(stderr) << "Subprocess I/O W!" << smsub_endl;
#endif #endif
const QByteArray readData = process.read(1024); const QByteArray readData = process.read(1024);
if (!readData.isEmpty()) if (!readData.isEmpty())
emit outputWritten(readData); emit outputWritten(readData);
#else }
}
else {
while (process.canReadLine()) { while (process.canReadLine()) {
#ifdef SMSUB_IODEBUG #ifdef SMSUB_IODEBUG
QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl; QTextStream(stderr) << "Subprocess I/O WL!" << smsub_endl;
@ -73,7 +76,7 @@ void SMSubProcess::readyRead()
const QByteArray readData = process.readLine().trimmed(); const QByteArray readData = process.readLine().trimmed();
emit outputWritten(readData + '\n'); emit outputWritten(readData + '\n');
} }
#endif }
} }
void SMSubProcess::processError(QProcess::ProcessError error) void SMSubProcess::processError(QProcess::ProcessError error)

View file

@ -26,11 +26,12 @@ class SMSubProcess : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int &termTimeout = 60000, const bool &keepAlive = false); SMSubProcess(const QString &executable, const QStringList &arguments, const QString &workingDirectory, const int termTimeout = 60000, const bool buffReads = false, const bool keepAlive = false);
private: private:
QProcess process; QProcess process;
int termTimeout; int termTimeout;
bool buffReads;
bool keepAlive; bool keepAlive;
public slots: public slots:

View file

@ -79,7 +79,7 @@ void SMSubServer::newConnection()
QObject::connect(webSocket, &QWebSocket::disconnected, this, &SMSubServer::deleteSocket); QObject::connect(webSocket, &QWebSocket::disconnected, this, &SMSubServer::deleteSocket);
webSocket->sendBinaryMessage(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8()); webSocket->sendBinaryMessage(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8());
socket = webSocket; socket = webSocket;
QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerName(), QString::number(webSocket->peerPort())) << smsub_endl; QTextStream(stderr) << QString("WebSocket %1:%2 connected!").arg(webSocket->peerAddress().toString(), QString::number(webSocket->peerPort())) << smsub_endl;
} }
else { else {
// Just for being sure // Just for being sure
@ -101,25 +101,26 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
// Only allow commands being sent if authenticated // Only allow commands being sent if authenticated
const bool isAuthenticated = socket->property("Authenticated").toBool(); const bool isAuthenticated = socket->property("Authenticated").toBool();
if (Q_LIKELY(isAuthenticated)) { if (Q_LIKELY(isAuthenticated)) {
if (message.startsWith("+dbg")) { if (message == "+dbg") {
socket->setProperty("ReceiveDbgMsg", true); socket->setProperty("ReceiveDbgMsg", true);
sendMessage(socket, "Debug messages enabled!\n"); sendMessage(socket, "Debug messages enabled!\n");
} }
else if (message.startsWith("-dbg")) { else if (message == "-dbg") {
socket->setProperty("ReceiveDbgMsg", false); socket->setProperty("ReceiveDbgMsg", false);
sendMessage(socket, "Debug messages disabled!\n"); sendMessage(socket, "Debug messages disabled!\n");
} }
else if (message.startsWith("+log")) { else if (message == "+log") {
socket->setProperty("ReceiveLog", true); socket->setProperty("ReceiveLog", true);
debugOutput(socket, "Log output enabled!"); debugOutput(socket, "Log output enabled!");
} }
else if (message.startsWith("-log")) { else if (message == "-log") {
socket->setProperty("ReceiveLog", false); socket->setProperty("ReceiveLog", false);
debugOutput(socket, "Log output disabled!"); debugOutput(socket, "Log output disabled!");
} }
else if (message.startsWith("+reg")) { else if (message == "+reg") {
if (Q_LIKELY(serverSettings->canRegister)) { if (Q_LIKELY(serverSettings->canRegister)) {
QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128); QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128) +
QUuid::createUuid().toByteArray(QUuid::Id128);
authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals); authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals);
emit tokenRegistered(QString::fromUtf8(authUuid)); emit tokenRegistered(QString::fromUtf8(authUuid));
sendMessage(socket, "Token: " + authUuid + '\n'); sendMessage(socket, "Token: " + authUuid + '\n');
@ -128,7 +129,7 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
sendMessage(socket, "Permission denied!\n"); sendMessage(socket, "Permission denied!\n");
} }
} }
else if (message.startsWith("status")) { else if (message == "status") {
if (status) { if (status) {
sendMessage(socket, QString("Status: on\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8()); sendMessage(socket, QString("Status: on\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
} }
@ -136,31 +137,31 @@ bool SMSubServer::messageReceived(QObject *socket, const QByteArray &message)
sendMessage(socket, QString("Status: off\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8()); sendMessage(socket, QString("Status: off\nLast Start: %1\nLast Stop: %2\n").arg(QString::number(startTime), QString::number(stopTime)).toUtf8());
} }
} }
else if (message.startsWith("start")) { else if (message == "start") {
emit startRequested(); emit startRequested();
debugOutput(socket, "Starting server!"); debugOutput(socket, "Starting server!");
} }
else if (message.startsWith("stop")) { else if (message == "stop") {
emit stopRequested(); emit stopRequested();
debugOutput(socket, "Stopping server!"); debugOutput(socket, "Stopping server!");
} }
else if (message.startsWith("kill")) { else if (message == "kill") {
emit killRequested(); emit killRequested();
debugOutput(socket, "Killing server!"); debugOutput(socket, "Killing server!");
} }
else if (message.startsWith("quit")) { else if (message == "quit") {
QTimer::singleShot(0, qApp, &QCoreApplication::quit); QTimer::singleShot(0, qApp, &QCoreApplication::quit);
debugOutput(socket, "Qutting smsub!"); debugOutput(socket, "Qutting smsub!");
} }
else if (message.startsWith("wl")) { else if (message.startsWith("wl ")) {
const QByteArray writeData = message.mid(3); const QByteArray writeData = message.mid(3);
emit inputWritten(writeData + '\n'); emit inputWritten(writeData + '\n');
debugOutput(socket, "Write line \"" + writeData + "\"!"); debugOutput(socket, "Write line: " + writeData);
} }
else if (message.startsWith("w")) { else if (message.startsWith("w ")) {
const QByteArray writeData = message.mid(2); const QByteArray writeData = message.mid(2);
emit inputWritten(writeData); emit inputWritten(writeData);
debugOutput(socket, "Write \"" + writeData + "\"!"); debugOutput(socket, "Write: " + writeData);
} }
} }
else { else {

View file

@ -134,7 +134,7 @@ int main(int argc, char *argv[])
{ {
QCoreApplication a(argc, argv); QCoreApplication a(argc, argv);
a.setApplicationName("Server Manager Subprocess"); a.setApplicationName("Server Manager Subprocess");
a.setApplicationVersion("0.8"); a.setApplicationVersion("0.9");
#ifdef Q_OS_UNIX #ifdef Q_OS_UNIX
catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM}); catchUnixSignals({SIGINT, SIGHUP, SIGQUIT, SIGTERM});
@ -142,9 +142,10 @@ int main(int argc, char *argv[])
bool rportSet = false; bool rportSet = false;
bool autoStart = true; bool autoStart = true;
bool buffReads = false;
bool keepAlive = false; bool keepAlive = false;
bool timeoutSet = false; bool timeoutSet = false;
int termTimeout = 60000; size_t termTimeout = 60000;
quint16 rport; quint16 rport;
QString socket; QString socket;
QString rsocket; QString rsocket;
@ -154,6 +155,7 @@ int main(int argc, char *argv[])
const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE"); const QByteArray envEnvironmentMode = qgetenv("SMSUB_ENVIRONMENT_MODE");
const QByteArray envAutoStart = qgetenv("SMSUB_AUTOSTART"); const QByteArray envAutoStart = qgetenv("SMSUB_AUTOSTART");
const QByteArray envBuffReads = qgetenv("SMSUB_BUFFERED_READS");
const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE"); const QByteArray envKeepAlive = qgetenv("SMSUB_KEEPALIVE");
const QByteArray envManifest = qgetenv("SMSUB_JSON"); const QByteArray envManifest = qgetenv("SMSUB_JSON");
const QByteArray envExecutable = qgetenv("SMSUB_EXEC"); const QByteArray envExecutable = qgetenv("SMSUB_EXEC");
@ -212,6 +214,12 @@ int main(int argc, char *argv[])
} }
} }
if (!envBuffReads.isEmpty()) {
if (envBuffReads == "1" || envBuffReads.toLower() == "true" || envBuffReads.toLower() == "yes") {
buffReads = true;
}
}
if (!envKeepAlive.isEmpty()) { if (!envKeepAlive.isEmpty()) {
if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") { if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
keepAlive = true; keepAlive = true;
@ -285,6 +293,12 @@ int main(int argc, char *argv[])
#endif #endif
commandLineParser.addOption(subprocessRemoteSocket); commandLineParser.addOption(subprocessRemoteSocket);
QCommandLineOption processAutoStart("autostart", "SMSub autostart mode setting.", "autostart");
commandLineParser.addOption(processAutoStart);
QCommandLineOption processKeepAlive("keepalive", "SMSub keepalive mode setting.", "keepalive");
commandLineParser.addOption(processKeepAlive);
QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout"); QCommandLineOption processTimeout("timeout", "SMSub termination timeout.", "timeout");
commandLineParser.addOption(processTimeout); commandLineParser.addOption(processTimeout);
@ -302,7 +316,7 @@ int main(int argc, char *argv[])
!envManifest.isEmpty() && !envArguments.isEmpty() || !envManifest.isEmpty() && !envArguments.isEmpty() ||
commandLineParser.isSet(processManifest) && !envArguments.isEmpty() || commandLineParser.isSet(processManifest) && !envArguments.isEmpty() ||
!envManifest.isEmpty() && commandLineParser.isSet(processArguments)) { !envManifest.isEmpty() && commandLineParser.isSet(processArguments)) {
QTextStream(stderr) << "You can't define a Process arguments and a JSON process manifest at the same time!" << smsub_endl; QTextStream(stderr) << "You can't define Process arguments and a JSON process manifest at the same time!" << smsub_endl;
return 1; return 1;
} }
@ -320,7 +334,7 @@ int main(int argc, char *argv[])
if (commandLineParser.isSet(processTimeout)) { if (commandLineParser.isSet(processTimeout)) {
bool ok; bool ok;
const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok); const int _termTimeout = commandLineParser.value(processTimeout).toInt(&ok, 10);
if (ok) { if (ok) {
termTimeout = _termTimeout; termTimeout = _termTimeout;
timeoutSet = true; timeoutSet = true;
@ -332,7 +346,7 @@ int main(int argc, char *argv[])
} }
else if (!envTimeout.isEmpty()) { else if (!envTimeout.isEmpty()) {
bool ok; bool ok;
const int _termTimeout = envTimeout.toInt(&ok); const int _termTimeout = envTimeout.toInt(&ok, 10);
if (ok) { if (ok) {
termTimeout = _termTimeout; termTimeout = _termTimeout;
timeoutSet = true; timeoutSet = true;
@ -350,13 +364,31 @@ int main(int argc, char *argv[])
executable = QString::fromUtf8(envExecutable); executable = QString::fromUtf8(envExecutable);
} }
if (!envAutoStart.isEmpty()) { if (commandLineParser.isSet(processAutoStart)) {
const QString claAutoStart = commandLineParser.value(processAutoStart);
if (claAutoStart == "0" || claAutoStart.toLower() == "false" || claAutoStart.toLower() == "no") {
autoStart = false;
}
}
else if (!envAutoStart.isEmpty()) {
if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") { if (envAutoStart == "0" || envAutoStart.toLower() == "false" || envAutoStart.toLower() == "no") {
autoStart = false; autoStart = false;
} }
} }
if (!envKeepAlive.isEmpty()) { if (!envBuffReads.isEmpty()) {
if (envBuffReads == "1" || envBuffReads.toLower() == "true" || envBuffReads.toLower() == "yes") {
buffReads = true;
}
}
if (commandLineParser.isSet(processKeepAlive)) {
const QString claKeepAlive = commandLineParser.value(processKeepAlive);
if (claKeepAlive != "0" || claKeepAlive.toLower() != "false" || claKeepAlive.toLower() != "no") {
keepAlive = true;
}
}
else if (!envKeepAlive.isEmpty()) {
if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") { if (envKeepAlive == "1" || envKeepAlive.toLower() == "true" || envKeepAlive.toLower() == "yes") {
keepAlive = true; keepAlive = true;
} }
@ -534,7 +566,7 @@ int main(int argc, char *argv[])
return 1; return 1;
} }
SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, keepAlive); SMSubProcess subProcess(executable, argumentList, workingDirectory, termTimeout, buffReads, keepAlive);
SMSubServerSettings remoteSettings; SMSubServerSettings remoteSettings;
remoteSettings.canRegister = false; remoteSettings.canRegister = false;