From 64c960fdb3e52e3e9cc4e937ba483a6b57f6fcbb Mon Sep 17 00:00:00 2001 From: Andrei Smirnov Date: Fri, 10 Sep 2021 11:54:51 +0300 Subject: [PATCH] Passing custom events over single instance IPC --- .../lib/include/DOtherSide/DOtherSide.h | 3 ++- .../DOtherSide/DOtherSideSingleInstance.h | 8 ++++++- vendor/DOtherSide/lib/src/DOtherSide.cpp | 4 ++-- .../lib/src/DOtherSideSingleInstance.cpp | 24 +++++++++++++++++-- 4 files changed, 33 insertions(+), 6 deletions(-) diff --git a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h index b97b367c06..e7e4ac2135 100644 --- a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h +++ b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSide.h @@ -983,8 +983,9 @@ DOS_API int DOS_CALL dos_qdeclarative_qmlregistersingletontype(const QmlRegister /// \brief Create a new SingleInstance class /// \param uniqueName The UTF-8 string for QLocalServer name +/// \param eventStr A custom string to be passed to the already running instance if detected /// \note The returned SingleInstance should be freed using the dos_singleinstance_delete() function -DOS_API DosSingleInstance *DOS_CALL dos_singleinstance_create(const char *uniqueName); +DOS_API DosSingleInstance *DOS_CALL dos_singleinstance_create(const char *uniqueName, const char *eventStr); /// \brief Returns bool indicating whether this is the first instance or not /// \returns true if this is the first instance diff --git a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h index 8051720093..f958036da7 100644 --- a/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h +++ b/vendor/DOtherSide/lib/include/DOtherSide/DOtherSideSingleInstance.h @@ -10,13 +10,19 @@ class SingleInstance : public QObject Q_OBJECT public: - explicit SingleInstance(const QString &uniqueName, QObject *parent = nullptr); + // uniqueName - the name of named pipe + // eventStr - optional event to send if another instance is detected + explicit SingleInstance(const QString &uniqueName, const QString &eventStr, QObject *parent = nullptr); ~SingleInstance() override; bool isFirstInstance() const; signals: void secondInstanceDetected(); + void eventReceived(const QString &eventStr); + +private slots: + void handleNewConnection(); private: QLocalServer *m_localServer; diff --git a/vendor/DOtherSide/lib/src/DOtherSide.cpp b/vendor/DOtherSide/lib/src/DOtherSide.cpp index 01781ae9d9..9d4b20d6d7 100644 --- a/vendor/DOtherSide/lib/src/DOtherSide.cpp +++ b/vendor/DOtherSide/lib/src/DOtherSide.cpp @@ -1333,9 +1333,9 @@ char *dos_qurl_replaceHostAndAddPath(char* url, char* newScheme, char* newHost, return convert_to_cstring(newQurl.toString()); } -DosSingleInstance *dos_singleinstance_create(const char *uniqueName) +DosSingleInstance *dos_singleinstance_create(const char *uniqueName, const char *eventStr) { - return new SingleInstance(QString::fromUtf8(uniqueName)); + return new SingleInstance(QString::fromUtf8(uniqueName), QString::fromUtf8(eventStr)); } void dos_singleinstance_delete(DosSingleInstance *vptr) diff --git a/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp b/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp index c5edcf21f5..762c9f5001 100644 --- a/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp +++ b/vendor/DOtherSide/lib/src/DOtherSideSingleInstance.cpp @@ -3,7 +3,11 @@ #include #include -SingleInstance::SingleInstance(const QString &uniqueName, QObject *parent) +namespace { + const int ReadWriteTimeoutMs = 1000; +} + +SingleInstance::SingleInstance(const QString &uniqueName, const QString &eventStr, QObject *parent) : QObject(parent) , m_localServer(new QLocalServer(this)) { @@ -19,7 +23,7 @@ SingleInstance::SingleInstance(const QString &uniqueName, QObject *parent) // the first instance start will be delayed by this timeout (ms) to ensure there are no other instances. // note: this is an ad-hoc timeout value selected based on prior experience. if (!localSocket.waitForConnected(100)) { - connect(m_localServer, &QLocalServer::newConnection, this, &SingleInstance::secondInstanceDetected); + connect(m_localServer, &QLocalServer::newConnection, this, &SingleInstance::handleNewConnection); // on *nix a crashed process will leave /tmp/xyz file preventing to start a new server. // therefore, if we were unable to connect, then we assume the server died and we need to clean up. // p.s. on Windows, this function does nothing. @@ -27,6 +31,9 @@ SingleInstance::SingleInstance(const QString &uniqueName, QObject *parent) if (!m_localServer->listen(socketName)) { qWarning() << "QLocalServer::listen(" << socketName << ") failed"; } + } else if (!eventStr.isEmpty()) { + localSocket.write(eventStr.toUtf8() + '\n'); + localSocket.waitForBytesWritten(ReadWriteTimeoutMs); } } @@ -41,3 +48,16 @@ bool SingleInstance::isFirstInstance() const { return m_localServer->isListening(); } + +void SingleInstance::handleNewConnection() +{ + emit secondInstanceDetected(); + + auto socket = m_localServer->nextPendingConnection(); + if (socket->waitForReadyRead(ReadWriteTimeoutMs) && socket->canReadLine()) { + auto event = socket->readLine(); + emit eventReceived(QString::fromUtf8(event)); + } + + socket->deleteLater(); +}