mirror of
https://github.com/dashpay/dash.git
synced 2024-12-25 12:02:48 +01:00
Reimplement click-to-pay links. Add OSX support.
Switch to using Qt's QLocalServer/QLocalSocket to handle bitcoin payment links (bitcoin:... URIs) Reason for switch: the boost::interprocess mechanism seemed flaky, and doesn't mesh as well with "The Qt Way" qtipcserver.cpp/h is replaced by paymentserver.cpp/h Click-to-pay now also works on OSX, with a custom Info.plist that registers Bitcoin-Qt as a handler for bitcoin: URLs and an event listener on the main QApplication that handles QFileOpenEvents (Qt translates 'url clicked' AppleEvents into QFileOpenEvents automagically).
This commit is contained in:
parent
2f0fa79db2
commit
8269a0953e
@ -2,6 +2,7 @@ TEMPLATE = app
|
|||||||
TARGET = bitcoin-qt
|
TARGET = bitcoin-qt
|
||||||
VERSION = 0.8.0
|
VERSION = 0.8.0
|
||||||
INCLUDEPATH += src src/json src/qt
|
INCLUDEPATH += src src/json src/qt
|
||||||
|
QT += network
|
||||||
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE
|
DEFINES += QT_GUI BOOST_THREAD_USE_LIB BOOST_SPIRIT_THREADSAFE
|
||||||
CONFIG += no_include_pwd
|
CONFIG += no_include_pwd
|
||||||
CONFIG += thread
|
CONFIG += thread
|
||||||
@ -195,7 +196,7 @@ HEADERS += src/qt/bitcoingui.h \
|
|||||||
src/qt/askpassphrasedialog.h \
|
src/qt/askpassphrasedialog.h \
|
||||||
src/protocol.h \
|
src/protocol.h \
|
||||||
src/qt/notificator.h \
|
src/qt/notificator.h \
|
||||||
src/qt/qtipcserver.h \
|
src/qt/paymentserver.h \
|
||||||
src/allocators.h \
|
src/allocators.h \
|
||||||
src/ui_interface.h \
|
src/ui_interface.h \
|
||||||
src/qt/rpcconsole.h \
|
src/qt/rpcconsole.h \
|
||||||
@ -264,7 +265,7 @@ SOURCES += src/qt/bitcoin.cpp src/qt/bitcoingui.cpp \
|
|||||||
src/qt/askpassphrasedialog.cpp \
|
src/qt/askpassphrasedialog.cpp \
|
||||||
src/protocol.cpp \
|
src/protocol.cpp \
|
||||||
src/qt/notificator.cpp \
|
src/qt/notificator.cpp \
|
||||||
src/qt/qtipcserver.cpp \
|
src/qt/paymentserver.cpp \
|
||||||
src/qt/rpcconsole.cpp \
|
src/qt/rpcconsole.cpp \
|
||||||
src/noui.cpp \
|
src/noui.cpp \
|
||||||
src/leveldb.cpp \
|
src/leveldb.cpp \
|
||||||
@ -385,6 +386,7 @@ macx:TARGET = "Bitcoin-Qt"
|
|||||||
macx:QMAKE_CFLAGS_THREAD += -pthread
|
macx:QMAKE_CFLAGS_THREAD += -pthread
|
||||||
macx:QMAKE_LFLAGS_THREAD += -pthread
|
macx:QMAKE_LFLAGS_THREAD += -pthread
|
||||||
macx:QMAKE_CXXFLAGS_THREAD += -pthread
|
macx:QMAKE_CXXFLAGS_THREAD += -pthread
|
||||||
|
macx:QMAKE_INFO_PLIST = share/qt/Info.plist
|
||||||
|
|
||||||
# Set libraries and includes at end, to use platform-defined defaults if not overridden
|
# Set libraries and includes at end, to use platform-defined defaults if not overridden
|
||||||
INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH $$QRENCODE_INCLUDE_PATH
|
INCLUDEPATH += $$BOOST_INCLUDE_PATH $$BDB_INCLUDE_PATH $$OPENSSL_INCLUDE_PATH $$QRENCODE_INCLUDE_PATH
|
||||||
|
31
share/qt/Info.plist
Normal file
31
share/qt/Info.plist
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
|
||||||
|
<plist version="0.9">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleIconFile</key>
|
||||||
|
<string>bitcoin.icns</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleGetInfoString</key>
|
||||||
|
<string>Bitcoin-Qt</string>
|
||||||
|
<key>CFBundleSignature</key>
|
||||||
|
<string>????</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>Bitcoin-Qt</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>org.bitcoinfoundation.Bitcoin-Qt</string>
|
||||||
|
<key>CFBundleURLTypes</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleTypeRole</key>
|
||||||
|
<string>Editor</string>
|
||||||
|
<key>CFBundleURLName</key>
|
||||||
|
<string>org.bitcoinfoundation.BitcoinPayment</string>
|
||||||
|
<key>CFBundleURLSchemes</key>
|
||||||
|
<array>
|
||||||
|
<string>bitcoin</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
@ -9,12 +9,13 @@
|
|||||||
#include "guiconstants.h"
|
#include "guiconstants.h"
|
||||||
#include "init.h"
|
#include "init.h"
|
||||||
#include "ui_interface.h"
|
#include "ui_interface.h"
|
||||||
#include "qtipcserver.h"
|
#include "paymentserver.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QLocale>
|
#include <QLocale>
|
||||||
|
#include <QTimer>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
#include <QSplashScreen>
|
#include <QSplashScreen>
|
||||||
#include <QLibraryInfo>
|
#include <QLibraryInfo>
|
||||||
@ -70,15 +71,6 @@ static bool ThreadSafeAskFee(int64 nFeeRequired)
|
|||||||
return payFee;
|
return payFee;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ThreadSafeHandleURI(const std::string& strURI)
|
|
||||||
{
|
|
||||||
if(!guiref)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QMetaObject::invokeMethod(guiref, "handleURI", GUIUtil::blockingGUIThreadConnection(),
|
|
||||||
Q_ARG(QString, QString::fromStdString(strURI)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitMessage(const std::string &message)
|
static void InitMessage(const std::string &message)
|
||||||
{
|
{
|
||||||
if(splashref)
|
if(splashref)
|
||||||
@ -117,14 +109,6 @@ int main(int argc, char *argv[])
|
|||||||
// Command-line options take precedence:
|
// Command-line options take precedence:
|
||||||
ParseParameters(argc, argv);
|
ParseParameters(argc, argv);
|
||||||
|
|
||||||
if(GetBoolArg("-testnet")) // Separate message queue name for testnet
|
|
||||||
strBitcoinURIQueueName = BITCOINURI_QUEUE_NAME_TESTNET;
|
|
||||||
else
|
|
||||||
strBitcoinURIQueueName = BITCOINURI_QUEUE_NAME_MAINNET;
|
|
||||||
|
|
||||||
// Do this early as we don't want to bother initializing if we are just calling IPC
|
|
||||||
ipcScanRelay(argc, argv);
|
|
||||||
|
|
||||||
// Internal string conversion is all UTF-8
|
// Internal string conversion is all UTF-8
|
||||||
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
|
||||||
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
|
QTextCodec::setCodecForCStrings(QTextCodec::codecForTr());
|
||||||
@ -132,6 +116,12 @@ int main(int argc, char *argv[])
|
|||||||
Q_INIT_RESOURCE(bitcoin);
|
Q_INIT_RESOURCE(bitcoin);
|
||||||
QApplication app(argc, argv);
|
QApplication app(argc, argv);
|
||||||
|
|
||||||
|
// Do this early as we don't want to bother initializing if we are just calling IPC
|
||||||
|
// ... but do it after creating app, so QCoreApplication::arguments is initialized:
|
||||||
|
if (PaymentServer::ipcSendCommandLine())
|
||||||
|
exit(0);
|
||||||
|
PaymentServer* paymentServer = new PaymentServer(&app);
|
||||||
|
|
||||||
// Install global event filter that makes sure that long tooltips can be word-wrapped
|
// Install global event filter that makes sure that long tooltips can be word-wrapped
|
||||||
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
|
app.installEventFilter(new GUIUtil::ToolTipToRichTextFilter(TOOLTIP_WRAP_THRESHOLD, &app));
|
||||||
|
|
||||||
@ -188,7 +178,6 @@ int main(int argc, char *argv[])
|
|||||||
// Subscribe to global signals from core
|
// Subscribe to global signals from core
|
||||||
uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
|
uiInterface.ThreadSafeMessageBox.connect(ThreadSafeMessageBox);
|
||||||
uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee);
|
uiInterface.ThreadSafeAskFee.connect(ThreadSafeAskFee);
|
||||||
uiInterface.ThreadSafeHandleURI.connect(ThreadSafeHandleURI);
|
|
||||||
uiInterface.InitMessage.connect(InitMessage);
|
uiInterface.InitMessage.connect(InitMessage);
|
||||||
uiInterface.QueueShutdown.connect(QueueShutdown);
|
uiInterface.QueueShutdown.connect(QueueShutdown);
|
||||||
uiInterface.Translate.connect(Translate);
|
uiInterface.Translate.connect(Translate);
|
||||||
@ -249,8 +238,10 @@ int main(int argc, char *argv[])
|
|||||||
window.show();
|
window.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Place this here as guiref has to be defined if we don't want to lose URIs
|
// Now that initialization/startup is done, process any command-line
|
||||||
ipcInit(argc, argv);
|
// bitcoin: URIs
|
||||||
|
QObject::connect(paymentServer, SIGNAL(receivedURI(QString)), &window, SLOT(handleURI(QString)));
|
||||||
|
QTimer::singleShot(100, paymentServer, SLOT(uiReady()));
|
||||||
|
|
||||||
app.exec();
|
app.exec();
|
||||||
|
|
||||||
|
159
src/qt/paymentserver.cpp
Normal file
159
src/qt/paymentserver.cpp
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// Copyright (c) 2009-2012 The Bitcoin developers
|
||||||
|
// Distributed under the MIT/X11 software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "paymentserver.h"
|
||||||
|
#include "guiconstants.h"
|
||||||
|
#include "ui_interface.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QCoreApplication>
|
||||||
|
#include <QDataStream>
|
||||||
|
#include <QDebug>
|
||||||
|
#include <QFileOpenEvent>
|
||||||
|
#include <QHash>
|
||||||
|
#include <QLocalServer>
|
||||||
|
#include <QLocalSocket>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
|
using namespace boost;
|
||||||
|
|
||||||
|
const int BITCOIN_IPC_CONNECT_TIMEOUT = 1000; // milliseconds
|
||||||
|
const QString BITCOIN_IPC_PREFIX("bitcoin:");
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create a name that is unique for:
|
||||||
|
// testnet / non-testnet
|
||||||
|
// data directory
|
||||||
|
//
|
||||||
|
static QString ipcServerName()
|
||||||
|
{
|
||||||
|
QString name("BitcoinQt");
|
||||||
|
|
||||||
|
// Append a simple hash of the datadir
|
||||||
|
// Note that GetDataDir(true) returns a different path
|
||||||
|
// for -testnet versus main net
|
||||||
|
QString ddir(GetDataDir(true).string().c_str());
|
||||||
|
name.append(QString::number(qHash(ddir)));
|
||||||
|
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// This stores payment requests received before
|
||||||
|
// the main GUI window is up and ready to ask the user
|
||||||
|
// to send payment.
|
||||||
|
//
|
||||||
|
static QStringList savedPaymentRequests;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Sending to the server is done synchronously, at startup.
|
||||||
|
// If the server isn't already running, startup continues,
|
||||||
|
// and the items in savedPaymentRequest will be handled
|
||||||
|
// when uiReady() is called.
|
||||||
|
//
|
||||||
|
bool PaymentServer::ipcSendCommandLine()
|
||||||
|
{
|
||||||
|
bool fResult = false;
|
||||||
|
|
||||||
|
const QStringList& args = QCoreApplication::arguments();
|
||||||
|
for (int i = 1; i < args.size(); i++)
|
||||||
|
{
|
||||||
|
if (!args[i].startsWith(BITCOIN_IPC_PREFIX, Qt::CaseInsensitive))
|
||||||
|
continue;
|
||||||
|
savedPaymentRequests.append(args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (const QString& arg, savedPaymentRequests)
|
||||||
|
{
|
||||||
|
QLocalSocket* socket = new QLocalSocket();
|
||||||
|
socket->connectToServer(ipcServerName(), QIODevice::WriteOnly);
|
||||||
|
if (!socket->waitForConnected(BITCOIN_IPC_CONNECT_TIMEOUT))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QByteArray block;
|
||||||
|
QDataStream out(&block, QIODevice::WriteOnly);
|
||||||
|
out.setVersion(QDataStream::Qt_4_0);
|
||||||
|
out << arg;
|
||||||
|
out.device()->seek(0);
|
||||||
|
socket->write(block);
|
||||||
|
socket->flush();
|
||||||
|
|
||||||
|
socket->waitForBytesWritten(BITCOIN_IPC_CONNECT_TIMEOUT);
|
||||||
|
socket->disconnectFromServer();
|
||||||
|
delete socket;
|
||||||
|
fResult = true;
|
||||||
|
}
|
||||||
|
return fResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
PaymentServer::PaymentServer(QApplication* parent) : QObject(parent), saveURIs(true)
|
||||||
|
{
|
||||||
|
// Install global event filter to catch QFileOpenEvents on the mac (sent when you click bitcoin: links)
|
||||||
|
parent->installEventFilter(this);
|
||||||
|
|
||||||
|
QString name = ipcServerName();
|
||||||
|
|
||||||
|
// Clean up old socket leftover from a crash:
|
||||||
|
QLocalServer::removeServer(name);
|
||||||
|
|
||||||
|
uriServer = new QLocalServer(this);
|
||||||
|
|
||||||
|
if (!uriServer->listen(name))
|
||||||
|
qDebug() << tr("Cannot start bitcoin: click-to-pay handler");
|
||||||
|
else
|
||||||
|
connect(uriServer, SIGNAL(newConnection()), this, SLOT(handleURIConnection()));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PaymentServer::eventFilter(QObject *object, QEvent *event)
|
||||||
|
{
|
||||||
|
// clicking on bitcoin: URLs creates FileOpen events on the Mac:
|
||||||
|
if (event->type() == QEvent::FileOpen)
|
||||||
|
{
|
||||||
|
QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event);
|
||||||
|
if (!fileEvent->url().isEmpty())
|
||||||
|
{
|
||||||
|
if (saveURIs) // Before main window is ready:
|
||||||
|
savedPaymentRequests.append(fileEvent->url().toString());
|
||||||
|
else
|
||||||
|
emit receivedURI(fileEvent->url().toString());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaymentServer::uiReady()
|
||||||
|
{
|
||||||
|
saveURIs = false;
|
||||||
|
foreach (const QString& s, savedPaymentRequests)
|
||||||
|
emit receivedURI(s);
|
||||||
|
savedPaymentRequests.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaymentServer::handleURIConnection()
|
||||||
|
{
|
||||||
|
QLocalSocket *clientConnection = uriServer->nextPendingConnection();
|
||||||
|
|
||||||
|
while (clientConnection->bytesAvailable() < (int)sizeof(quint32))
|
||||||
|
clientConnection->waitForReadyRead();
|
||||||
|
|
||||||
|
connect(clientConnection, SIGNAL(disconnected()),
|
||||||
|
clientConnection, SLOT(deleteLater()));
|
||||||
|
|
||||||
|
QDataStream in(clientConnection);
|
||||||
|
in.setVersion(QDataStream::Qt_4_0);
|
||||||
|
if (clientConnection->bytesAvailable() < (int)sizeof(quint16)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
QString message;
|
||||||
|
in >> message;
|
||||||
|
|
||||||
|
if (saveURIs)
|
||||||
|
savedPaymentRequests.append(message);
|
||||||
|
else
|
||||||
|
emit receivedURI(message);
|
||||||
|
}
|
66
src/qt/paymentserver.h
Normal file
66
src/qt/paymentserver.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
#ifndef PAYMENTSERVER_H
|
||||||
|
#define PAYMENTSERVER_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// This class handles payment requests from clicking on
|
||||||
|
// bitcoin: URIs
|
||||||
|
//
|
||||||
|
// This is somewhat tricky, because we have to deal with
|
||||||
|
// the situation where the user clicks on a link during
|
||||||
|
// startup/initialization, when the splash-screen is up
|
||||||
|
// but the main window (and the Send Coins tab) is not.
|
||||||
|
//
|
||||||
|
// So, the strategy is:
|
||||||
|
//
|
||||||
|
// Create the server, and register the event handler,
|
||||||
|
// when the application is created. Save any URIs
|
||||||
|
// received at or during startup in a list.
|
||||||
|
//
|
||||||
|
// When startup is finished and the main window is
|
||||||
|
// show, a signal is sent to slot uiReady(), which
|
||||||
|
// emits a receivedURL() signal for any payment
|
||||||
|
// requests that happened during startup.
|
||||||
|
//
|
||||||
|
// After startup, receivedURL() happens as usual.
|
||||||
|
//
|
||||||
|
// This class has one more feature: a static
|
||||||
|
// method that finds URIs passed in the command line
|
||||||
|
// and, if a server is running in another process,
|
||||||
|
// sends them to the server.
|
||||||
|
//
|
||||||
|
#include <QObject>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class QApplication;
|
||||||
|
class QLocalServer;
|
||||||
|
|
||||||
|
class PaymentServer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
private:
|
||||||
|
bool saveURIs;
|
||||||
|
QLocalServer* uriServer;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Returns true if there were URIs on the command line
|
||||||
|
// which were successfully sent to an already-running
|
||||||
|
// process.
|
||||||
|
static bool ipcSendCommandLine();
|
||||||
|
|
||||||
|
PaymentServer(QApplication* parent);
|
||||||
|
|
||||||
|
bool eventFilter(QObject *object, QEvent *event);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void receivedURI(QString);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// Signal this when the main window's UI is ready
|
||||||
|
// to display payment requests to the user
|
||||||
|
void uiReady();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void handleURIConnection();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // PAYMENTSERVER_H
|
@ -1,165 +0,0 @@
|
|||||||
// Copyright (c) 2009-2012 The Bitcoin developers
|
|
||||||
// Distributed under the MIT/X11 software license, see the accompanying
|
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
||||||
|
|
||||||
#include <boost/version.hpp>
|
|
||||||
#if defined(WIN32) && BOOST_VERSION == 104900
|
|
||||||
#define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME
|
|
||||||
#define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "qtipcserver.h"
|
|
||||||
#include "guiconstants.h"
|
|
||||||
#include "ui_interface.h"
|
|
||||||
#include "util.h"
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
||||||
#include <boost/interprocess/ipc/message_queue.hpp>
|
|
||||||
#include <boost/version.hpp>
|
|
||||||
|
|
||||||
#if defined(WIN32) && (!defined(BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME) || !defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) || BOOST_VERSION < 104900)
|
|
||||||
#warning Compiling without BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME and BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME uncommented in boost/interprocess/detail/tmp_dir_helpers.hpp or using a boost version before 1.49 may have unintended results see svn.boost.org/trac/boost/ticket/5392
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace boost;
|
|
||||||
using namespace boost::interprocess;
|
|
||||||
using namespace boost::posix_time;
|
|
||||||
|
|
||||||
// holds Bitcoin-Qt message queue name (initialized in bitcoin.cpp)
|
|
||||||
std::string strBitcoinURIQueueName;
|
|
||||||
|
|
||||||
#if defined MAC_OSX || defined __FreeBSD__
|
|
||||||
// URI handling not implemented on OSX yet
|
|
||||||
|
|
||||||
void ipcScanRelay(int argc, char *argv[]) { }
|
|
||||||
void ipcInit(int argc, char *argv[]) { }
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static void ipcThread2(void* pArg);
|
|
||||||
|
|
||||||
static bool ipcScanCmd(int argc, char *argv[], bool fRelay)
|
|
||||||
{
|
|
||||||
// Check for URI in argv
|
|
||||||
bool fSent = false;
|
|
||||||
for (int i = 1; i < argc; i++)
|
|
||||||
{
|
|
||||||
if (boost::algorithm::istarts_with(argv[i], "bitcoin:"))
|
|
||||||
{
|
|
||||||
const char *strURI = argv[i];
|
|
||||||
try {
|
|
||||||
boost::interprocess::message_queue mq(boost::interprocess::open_only, strBitcoinURIQueueName.c_str());
|
|
||||||
if (mq.try_send(strURI, strlen(strURI), 0))
|
|
||||||
fSent = true;
|
|
||||||
else if (fRelay)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
catch (boost::interprocess::interprocess_exception &ex) {
|
|
||||||
// don't log the "file not found" exception, because that's normal for
|
|
||||||
// the first start of the first instance
|
|
||||||
if (ex.get_error_code() != boost::interprocess::not_found_error || !fRelay)
|
|
||||||
{
|
|
||||||
printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fSent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ipcScanRelay(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
if (ipcScanCmd(argc, argv, true))
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipcThread(void* pArg)
|
|
||||||
{
|
|
||||||
// Make this thread recognisable as the GUI-IPC thread
|
|
||||||
RenameThread("bitcoin-gui-ipc");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ipcThread2(pArg);
|
|
||||||
}
|
|
||||||
catch (std::exception& e) {
|
|
||||||
PrintExceptionContinue(&e, "ipcThread()");
|
|
||||||
} catch (...) {
|
|
||||||
PrintExceptionContinue(NULL, "ipcThread()");
|
|
||||||
}
|
|
||||||
printf("ipcThread exited\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ipcThread2(void* pArg)
|
|
||||||
{
|
|
||||||
printf("ipcThread started\n");
|
|
||||||
|
|
||||||
message_queue* mq = (message_queue*)pArg;
|
|
||||||
char buffer[MAX_URI_LENGTH + 1] = "";
|
|
||||||
size_t nSize = 0;
|
|
||||||
unsigned int nPriority = 0;
|
|
||||||
|
|
||||||
loop
|
|
||||||
{
|
|
||||||
ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100);
|
|
||||||
if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d))
|
|
||||||
{
|
|
||||||
uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize));
|
|
||||||
Sleep(1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fShutdown)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove message queue
|
|
||||||
message_queue::remove(strBitcoinURIQueueName.c_str());
|
|
||||||
// Cleanup allocated memory
|
|
||||||
delete mq;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ipcInit(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
message_queue* mq = NULL;
|
|
||||||
char buffer[MAX_URI_LENGTH + 1] = "";
|
|
||||||
size_t nSize = 0;
|
|
||||||
unsigned int nPriority = 0;
|
|
||||||
|
|
||||||
try {
|
|
||||||
mq = new message_queue(open_or_create, strBitcoinURIQueueName.c_str(), 2, MAX_URI_LENGTH);
|
|
||||||
|
|
||||||
// Make sure we don't lose any bitcoin: URIs
|
|
||||||
for (int i = 0; i < 2; i++)
|
|
||||||
{
|
|
||||||
ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1);
|
|
||||||
if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d))
|
|
||||||
{
|
|
||||||
uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure only one bitcoin instance is listening
|
|
||||||
message_queue::remove(strBitcoinURIQueueName.c_str());
|
|
||||||
delete mq;
|
|
||||||
|
|
||||||
mq = new message_queue(open_or_create, strBitcoinURIQueueName.c_str(), 2, MAX_URI_LENGTH);
|
|
||||||
}
|
|
||||||
catch (interprocess_exception &ex) {
|
|
||||||
printf("ipcInit() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NewThread(ipcThread, mq))
|
|
||||||
{
|
|
||||||
delete mq;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ipcScanCmd(argc, argv, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,16 +0,0 @@
|
|||||||
#ifndef QTIPCSERVER_H
|
|
||||||
#define QTIPCSERVER_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
// Define Bitcoin-Qt message queue name for mainnet
|
|
||||||
#define BITCOINURI_QUEUE_NAME_MAINNET "BitcoinURI"
|
|
||||||
// Define Bitcoin-Qt message queue name for testnet
|
|
||||||
#define BITCOINURI_QUEUE_NAME_TESTNET "BitcoinURI-testnet"
|
|
||||||
|
|
||||||
extern std::string strBitcoinURIQueueName;
|
|
||||||
|
|
||||||
void ipcScanRelay(int argc, char *argv[]);
|
|
||||||
void ipcInit(int argc, char *argv[]);
|
|
||||||
|
|
||||||
#endif // QTIPCSERVER_H
|
|
Loading…
Reference in New Issue
Block a user