summaryrefslogtreecommitdiff
path: root/src/multiprocess.cpp
diff options
context:
space:
mode:
authorQudix <17361645+Qudix@users.noreply.github.com>2020-11-09 13:02:01 -0600
committerQudix <17361645+Qudix@users.noreply.github.com>2020-11-09 13:02:01 -0600
commit0a3bdad8afd18a21a3697804ae344abd09e3712e (patch)
tree0bf234b41dff43cdfe39afea48c7c1d8bdd995c2 /src/multiprocess.cpp
parentb7b843d42badab83b262260035658259f24e4f9a (diff)
parentfef8543a58b4226242ce26c4c8876abaa64394cb (diff)
Merge branch 'master' of https://github.com/ModOrganizer2/modorganizer into master
Diffstat (limited to 'src/multiprocess.cpp')
-rw-r--r--src/multiprocess.cpp102
1 files changed, 102 insertions, 0 deletions
diff --git a/src/multiprocess.cpp b/src/multiprocess.cpp
new file mode 100644
index 00000000..4ce58718
--- /dev/null
+++ b/src/multiprocess.cpp
@@ -0,0 +1,102 @@
+#include "multiprocess.h"
+#include "utility.h"
+#include <report.h>
+#include <log.h>
+#include <QLocalSocket>
+
+static const char s_Key[] = "mo-43d1a3ad-eeb0-4818-97c9-eda5216c29b5";
+static const int s_Timeout = 5000;
+
+using MOBase::reportError;
+
+MOMultiProcess::MOMultiProcess(bool allowMultiple, QObject *parent) :
+ QObject(parent), m_Ephemeral(false), m_OwnsSM(false)
+{
+ m_SharedMem.setKey(s_Key);
+
+ if (!m_SharedMem.create(1)) {
+ if (m_SharedMem.error() == QSharedMemory::AlreadyExists) {
+ if (!allowMultiple) {
+ m_SharedMem.attach();
+ m_Ephemeral = true;
+ }
+ }
+
+ if ((m_SharedMem.error() != QSharedMemory::NoError) &&
+ (m_SharedMem.error() != QSharedMemory::AlreadyExists)) {
+ throw MOBase::MyException(tr("SHM error: %1").arg(m_SharedMem.errorString()));
+ }
+ } else {
+ m_OwnsSM = true;
+ }
+
+ if (m_OwnsSM) {
+ connect(&m_Server, SIGNAL(newConnection()), this, SLOT(receiveMessage()), Qt::QueuedConnection);
+ // has to be called before listen
+ m_Server.setSocketOptions(QLocalServer::WorldAccessOption);
+ m_Server.listen(s_Key);
+ }
+}
+
+
+void MOMultiProcess::sendMessage(const QString &message)
+{
+ if (m_OwnsSM) {
+ // nobody there to receive the message
+ return;
+ }
+ QLocalSocket socket(this);
+
+ bool connected = false;
+ for(int i = 0; i < 2 && !connected; ++i) {
+ if (i > 0) {
+ Sleep(250);
+ }
+
+ // other process may be just starting up
+ socket.connectToServer(s_Key, QIODevice::WriteOnly);
+ connected = socket.waitForConnected(s_Timeout);
+ }
+
+ if (!connected) {
+ reportError(tr("failed to connect to running process: %1").arg(socket.errorString()));
+ return;
+ }
+
+ socket.write(message.toUtf8());
+ if (!socket.waitForBytesWritten(s_Timeout)) {
+ reportError(tr("failed to communicate with running process: %1").arg(socket.errorString()));
+ return;
+ }
+
+ socket.disconnectFromServer();
+ socket.waitForDisconnected();
+}
+
+void MOMultiProcess::receiveMessage()
+{
+ QLocalSocket *socket = m_Server.nextPendingConnection();
+ if (!socket) {
+ return;
+ }
+
+ if (!socket->waitForReadyRead(s_Timeout)) {
+ // check if there are bytes available; if so, it probably means the data was
+ // already received by the time waitForReadyRead() was called and the
+ // connection has been closed
+ const auto av = socket->bytesAvailable();
+
+ if (av <= 0) {
+ MOBase::log::error(
+ "failed to receive data from secondary process: {}",
+ socket->errorString());
+
+ reportError(tr("failed to receive data from secondary process: %1").arg(socket->errorString()));
+ return;
+ }
+ }
+
+ QString message = QString::fromUtf8(socket->readAll().constData());
+ emit messageSent(message);
+ socket->disconnectFromServer();
+}