diff options
| author | dsc <xmrdsc@protonmail.com> | 2019-03-22 21:02:08 +0100 |
|---|---|---|
| committer | xmrdsc <xmrdsc@protonmail.com> | 2019-04-29 19:56:46 +0200 |
| commit | 18f2accc7f5ac0941c703a7cb4dd9cab2a2bca77 (patch) | |
| tree | b1aeea40a02d76c352097dde7514b849c0e91483 /src/qt | |
| parent | ff6ce6294b561a6f15769a8e7a8270d57d02f8de (diff) | |
| download | monzero-gui-18f2accc7f5ac0941c703a7cb4dd9cab2a2bca77.tar.gz monzero-gui-18f2accc7f5ac0941c703a7cb4dd9cab2a2bca77.tar.xz monzero-gui-18f2accc7f5ac0941c703a7cb4dd9cab2a2bca77.zip | |
IPC and custom protocol handler for monero://
Diffstat (limited to 'src/qt')
| -rw-r--r-- | src/qt/ipc.cpp | 106 | ||||
| -rw-r--r-- | src/qt/ipc.h | 35 | ||||
| -rw-r--r-- | src/qt/mime.cpp | 42 | ||||
| -rw-r--r-- | src/qt/mime.h | 8 | ||||
| -rw-r--r-- | src/qt/utils.cpp | 20 | ||||
| -rw-r--r-- | src/qt/utils.h | 11 |
6 files changed, 222 insertions, 0 deletions
diff --git a/src/qt/ipc.cpp b/src/qt/ipc.cpp new file mode 100644 index 00000000..c7d1aa86 --- /dev/null +++ b/src/qt/ipc.cpp @@ -0,0 +1,106 @@ +#include <QCoreApplication> +#include <QLocalSocket> +#include <QLocalServer> +#include <QtNetwork> +#include <QDebug> + +#include "ipc.h" +#include "utils.h" + +// Start listening for incoming IPC commands on UDS (Unix) or named pipe (Windows) +void IPC::bind(){ + QString path = QString(this->m_socketFile.absoluteFilePath()); + qDebug() << path; + + this->m_server = new QLocalServer(this); + this->m_server->setSocketOptions(QLocalServer::UserAccessOption); + + bool restarted = false; + if(!this->m_server->listen(path)){ + // On Unix if the server crashes without closing listen will fail with AddressInUseError. + // To create a new server the file should be removed. On Windows two local servers can listen + // to the same pipe at the same time, but any connections will go to one of the server. +#ifdef Q_OS_UNIX + qDebug() << QString("Unable to start IPC server in \"%1\": \"%2\". Retrying.").arg(path).arg(this->m_server->errorString()); + if(this->m_socketFile.exists()){ + QFile file(path); + file.remove(); + + if(this->m_server->listen(path)){ + restarted = true; + } + } +#endif + if(!restarted) + qDebug() << QString("Unable to start IPC server in \"%1\": \"%2\".").arg(path).arg(this->m_server->errorString()); + } + + connect(this->m_server, &QLocalServer::newConnection, this, &IPC::handleConnection); +} + +// Process incoming IPC command. First check if monero-wallet-gui is +// already running. If it is, send it to that instance instead, if not, +// queue the command for later use inside our QML engine. Returns true +// when queued, false if sent to another instance, at which point we can +// kill the current process. +bool IPC::saveCommand(QString cmdString){ + qDebug() << QString("saveCommand called: %1").arg(cmdString); + + QLocalSocket ls; + QByteArray buffer; + buffer = buffer.append(cmdString); + QString socketFilePath = this->socketFile().filePath(); + + ls.connectToServer(socketFilePath, QIODevice::WriteOnly); + if(ls.waitForConnected(1000)){ + ls.write(buffer); + if (!ls.waitForBytesWritten(1000)){ + qDebug() << QString("Could not send command \"%1\" over IPC %2: \"%3\"").arg(cmdString, socketFilePath, ls.errorString()); + return false; + } + + qDebug() << QString("Sent command \"%1\" over IPC \"%2\"").arg(cmdString, socketFilePath); + return false; + } + + if(ls.isOpen()) + ls.disconnectFromServer(); + + // Queue for later + this->SetQueuedCmd(cmdString); + return true; +} + +bool IPC::saveCommand(const QUrl &url){; + this->saveCommand(url.toString()); +} + +void IPC::handleConnection(){ + QLocalSocket *clientConnection = this->m_server->nextPendingConnection(); + connect(clientConnection, &QLocalSocket::disconnected, + clientConnection, &QLocalSocket::deleteLater); + + clientConnection->waitForReadyRead(2); + QByteArray cmdArray = clientConnection->readAll(); + QString cmdString = QTextCodec::codecForMib(106)->toUnicode(cmdArray); // UTF-8 + qDebug() << cmdString; + + this->parseCommand(cmdString); + + clientConnection->close(); + delete clientConnection; +} + +void IPC::parseCommand(const QUrl &url){ + this->parseCommand(url.toString()); +} + +void IPC::parseCommand(QString cmdString){ + if(cmdString.contains(reURI)){ + this->emitUriHandler(cmdString); + } +} + +void IPC::emitUriHandler(QString uriString){ + emit uriHandler(uriString); +} diff --git a/src/qt/ipc.h b/src/qt/ipc.h new file mode 100644 index 00000000..5c3cc73a --- /dev/null +++ b/src/qt/ipc.h @@ -0,0 +1,35 @@ +#ifndef IPC_H +#define IPC_H + +#include <QtCore> +#include <QLocalServer> +#include <qt/utils.h> + +class IPC : public QObject +{ +Q_OBJECT +public: + IPC(QObject *parent = 0) : QObject(parent) {} + QFileInfo socketFile() const { return m_socketFile; } + Q_INVOKABLE QString queuedCmd() { return m_queuedCmd; } + void SetQueuedCmd(const QString cmdString) { m_queuedCmd = cmdString; } + +public slots: + void bind(); + void handleConnection(); + bool saveCommand(QString cmdString); + bool saveCommand(const QUrl &url); + void parseCommand(QString cmdString); + void parseCommand(const QUrl &url); + void emitUriHandler(QString uriString); + +signals: + void uriHandler(QString uriString); + +private: + QLocalServer *m_server; + QString m_queuedCmd; + QFileInfo m_socketFile = QFileInfo(QString(QDir::tempPath() + "/xmr-gui_%2.sock").arg(getAccountName())); +}; + +#endif // IPC_H diff --git a/src/qt/mime.cpp b/src/qt/mime.cpp new file mode 100644 index 00000000..76fbb19c --- /dev/null +++ b/src/qt/mime.cpp @@ -0,0 +1,42 @@ +#include <QtCore> +#include <QApplication> +#include <QFile> +#include <QTextStream> + +#include "mime.h" +#include "utils.h" + +void registerXdgMime(QApplication &app){ + // MacOS handled via Info.plist + // Windows handled in the installer by rbrunner7 + + QString xdg = QString( + "[Desktop Entry]\n" + "Name=Monero GUI\n" + "GenericName=Monero-GUI\n" + "X-GNOME-FullName=Monero-GUI\n" + "Comment=Monero GUI\n" + "Keywords=Monero;\n" + "Exec=%1 %u\n" + "Terminal=false\n" + "Type=Application\n" + "Icon=monero\n" + "Categories=Network;GNOME;Qt;\n" + "MimeType=x-scheme-handler/monero;x-scheme-handler/moneroseed\n" + "StartupNotify=true\n" + "X-GNOME-Bugzilla-Bugzilla=GNOME\n" + "X-GNOME-UsesNotifications=true\n" + ).arg(app.applicationFilePath()); + + QString appPath = QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation); + QString filePath = QString("%1/monero-gui.desktop").arg(appPath); + + qDebug() << QString("Writing %1").arg(filePath); + QFile file(filePath); + if(file.open(QIODevice::WriteOnly)){ + QTextStream out(&file); out << xdg << endl; + file.close(); + } + else + file.close(); +} diff --git a/src/qt/mime.h b/src/qt/mime.h new file mode 100644 index 00000000..a6c79587 --- /dev/null +++ b/src/qt/mime.h @@ -0,0 +1,8 @@ +#ifndef MIME_H +#define MIME_H + +#include <QApplication> + +void registerXdgMime(QApplication &app); + +#endif // MIME_H diff --git a/src/qt/utils.cpp b/src/qt/utils.cpp new file mode 100644 index 00000000..cb0ad4f9 --- /dev/null +++ b/src/qt/utils.cpp @@ -0,0 +1,20 @@ +#include <QtCore> + +#include "utils.h" + +bool fileExists(QString path) { + QFileInfo check_file(path); + if (check_file.exists() && check_file.isFile()) + return true; + else + return false; +} + +QString getAccountName(){ + QString accountName = qgetenv("USER"); // mac/linux + if (accountName.isEmpty()) + accountName = qgetenv("USERNAME"); // Windows + if (accountName.isEmpty()) + accountName = "My monero Account"; + return accountName; +} diff --git a/src/qt/utils.h b/src/qt/utils.h new file mode 100644 index 00000000..6a014ffc --- /dev/null +++ b/src/qt/utils.h @@ -0,0 +1,11 @@ +#ifndef UTILS_H +#define UTILS_H + +#include <QtCore> +#include <QRegExp> + +bool fileExists(QString path); +QString getAccountName(); +const static QRegExp reURI = QRegExp("^\\w+:\\/\\/([\\w+\\-?\\-_\\-=\\-&]+)"); + +#endif // UTILS_H |
