Implement RPCTimerHandler for Qt RPC console
Implement RPCTimerHandler for Qt RPC console, so that `walletpassphrase` works with GUI and `-server=0`. Also simplify HTTPEvent-related code by using boost::function directly.
This commit is contained in:
parent
57d85d9bee
commit
be33f3f50b
7 changed files with 67 additions and 50 deletions
|
@ -19,24 +19,16 @@
|
||||||
class HTTPRPCTimer : public RPCTimerBase
|
class HTTPRPCTimer : public RPCTimerBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t seconds) : ev(eventBase, false, new Handler(func))
|
HTTPRPCTimer(struct event_base* eventBase, boost::function<void(void)>& func, int64_t millis) :
|
||||||
|
ev(eventBase, false, func)
|
||||||
{
|
{
|
||||||
struct timeval tv = {seconds, 0};
|
struct timeval tv;
|
||||||
|
tv.tv_sec = millis/1000;
|
||||||
|
tv.tv_usec = (millis%1000)*1000;
|
||||||
ev.trigger(&tv);
|
ev.trigger(&tv);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
HTTPEvent ev;
|
HTTPEvent ev;
|
||||||
|
|
||||||
class Handler : public HTTPClosure
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Handler(const boost::function<void(void)>& func) : func(func)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
boost::function<void(void)> func;
|
|
||||||
void operator()() { func(); }
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HTTPRPCTimerInterface : public RPCTimerInterface
|
class HTTPRPCTimerInterface : public RPCTimerInterface
|
||||||
|
@ -49,9 +41,9 @@ public:
|
||||||
{
|
{
|
||||||
return "HTTP";
|
return "HTTP";
|
||||||
}
|
}
|
||||||
RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t seconds)
|
RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
|
||||||
{
|
{
|
||||||
return new HTTPRPCTimer(base, func, seconds);
|
return new HTTPRPCTimer(base, func, millis);
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
struct event_base* base;
|
struct event_base* base;
|
||||||
|
|
|
@ -412,18 +412,15 @@ struct event_base* EventBase()
|
||||||
|
|
||||||
static void httpevent_callback_fn(evutil_socket_t, short, void* data)
|
static void httpevent_callback_fn(evutil_socket_t, short, void* data)
|
||||||
{
|
{
|
||||||
// Static handler simply passes through execution flow to _handle method
|
// Static handler: simply call inner handler
|
||||||
((HTTPEvent*)data)->_handle();
|
HTTPEvent *self = ((HTTPEvent*)data);
|
||||||
|
self->handler();
|
||||||
|
if (self->deleteWhenTriggered)
|
||||||
|
delete self;
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPEvent::_handle()
|
HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
|
||||||
{
|
deleteWhenTriggered(deleteWhenTriggered), handler(handler)
|
||||||
(*handler)();
|
|
||||||
if (deleteWhenTriggered)
|
|
||||||
delete this;
|
|
||||||
}
|
|
||||||
|
|
||||||
HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, HTTPClosure* handler) : deleteWhenTriggered(deleteWhenTriggered), handler(handler)
|
|
||||||
{
|
{
|
||||||
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
|
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
|
||||||
assert(ev);
|
assert(ev);
|
||||||
|
@ -496,20 +493,6 @@ void HTTPRequest::WriteHeader(const std::string& hdr, const std::string& value)
|
||||||
* Replies must be sent in the main loop in the main http thread,
|
* Replies must be sent in the main loop in the main http thread,
|
||||||
* this cannot be done from worker threads.
|
* this cannot be done from worker threads.
|
||||||
*/
|
*/
|
||||||
struct HTTPSendReplyHandler : HTTPClosure {
|
|
||||||
public:
|
|
||||||
HTTPSendReplyHandler(struct evhttp_request* req, int nStatus) : req(req), nStatus(nStatus)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
void operator()()
|
|
||||||
{
|
|
||||||
evhttp_send_reply(req, nStatus, NULL, NULL);
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
struct evhttp_request* req;
|
|
||||||
int nStatus;
|
|
||||||
};
|
|
||||||
|
|
||||||
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
|
void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
|
||||||
{
|
{
|
||||||
assert(!replySent && req);
|
assert(!replySent && req);
|
||||||
|
@ -518,7 +501,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
|
||||||
assert(evb);
|
assert(evb);
|
||||||
evbuffer_add(evb, strReply.data(), strReply.size());
|
evbuffer_add(evb, strReply.data(), strReply.size());
|
||||||
HTTPEvent* ev = new HTTPEvent(eventBase, true,
|
HTTPEvent* ev = new HTTPEvent(eventBase, true,
|
||||||
new HTTPSendReplyHandler(req, nStatus));
|
boost::bind(evhttp_send_reply, req, nStatus, (const char*)NULL, (struct evbuffer *)NULL));
|
||||||
ev->trigger(0);
|
ev->trigger(0);
|
||||||
replySent = true;
|
replySent = true;
|
||||||
req = 0; // transferred back to main thread
|
req = 0; // transferred back to main thread
|
||||||
|
|
|
@ -117,8 +117,11 @@ public:
|
||||||
class HTTPEvent
|
class HTTPEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Create a new event */
|
/** Create a new event.
|
||||||
HTTPEvent(struct event_base* base, bool deleteWhenTriggered, HTTPClosure* handler);
|
* deleteWhenTriggered deletes this event object after the event is triggered (and the handler called)
|
||||||
|
* handler is the handler to call when the event is triggered.
|
||||||
|
*/
|
||||||
|
HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler);
|
||||||
~HTTPEvent();
|
~HTTPEvent();
|
||||||
|
|
||||||
/** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
|
/** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
|
||||||
|
@ -126,13 +129,10 @@ public:
|
||||||
*/
|
*/
|
||||||
void trigger(struct timeval* tv);
|
void trigger(struct timeval* tv);
|
||||||
|
|
||||||
/** Internal function for handling, do not call directly */
|
|
||||||
void _handle();
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool deleteWhenTriggered;
|
bool deleteWhenTriggered;
|
||||||
|
boost::function<void(void)> handler;
|
||||||
|
private:
|
||||||
struct event* ev;
|
struct event* ev;
|
||||||
boost::scoped_ptr<HTTPClosure> handler;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_HTTPSERVER_H
|
#endif // BITCOIN_HTTPSERVER_H
|
||||||
|
|
|
@ -28,6 +28,7 @@
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
#include <QTime>
|
#include <QTime>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#if QT_VERSION < 0x050000
|
#if QT_VERSION < 0x050000
|
||||||
#include <QUrl>
|
#include <QUrl>
|
||||||
|
@ -66,6 +67,40 @@ Q_SIGNALS:
|
||||||
void reply(int category, const QString &command);
|
void reply(int category, const QString &command);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Class for handling RPC timers
|
||||||
|
* (used for e.g. re-locking the wallet after a timeout)
|
||||||
|
*/
|
||||||
|
class QtRPCTimerBase: public QObject, public RPCTimerBase
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
QtRPCTimerBase(boost::function<void(void)>& func, int64_t millis):
|
||||||
|
func(func)
|
||||||
|
{
|
||||||
|
timer.setSingleShot(true);
|
||||||
|
connect(&timer, SIGNAL(timeout()), this, SLOT(timeout()));
|
||||||
|
timer.start(millis);
|
||||||
|
}
|
||||||
|
~QtRPCTimerBase() {}
|
||||||
|
private Q_SLOTS:
|
||||||
|
void timeout() { func(); }
|
||||||
|
private:
|
||||||
|
QTimer timer;
|
||||||
|
boost::function<void(void)> func;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QtRPCTimerInterface: public RPCTimerInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~QtRPCTimerInterface() {}
|
||||||
|
const char *Name() { return "Qt"; }
|
||||||
|
RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis)
|
||||||
|
{
|
||||||
|
return new QtRPCTimerBase(func, millis);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
#include "rpcconsole.moc"
|
#include "rpcconsole.moc"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -232,6 +267,9 @@ RPCConsole::RPCConsole(const PlatformStyle *platformStyle, QWidget *parent) :
|
||||||
ui->label_berkeleyDBVersion->hide();
|
ui->label_berkeleyDBVersion->hide();
|
||||||
ui->berkeleyDBVersion->hide();
|
ui->berkeleyDBVersion->hide();
|
||||||
#endif
|
#endif
|
||||||
|
// Register RPC timer interface
|
||||||
|
rpcTimerInterface = new QtRPCTimerInterface();
|
||||||
|
RPCRegisterTimerInterface(rpcTimerInterface);
|
||||||
|
|
||||||
startExecutor();
|
startExecutor();
|
||||||
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
|
setTrafficGraphRange(INITIAL_TRAFFIC_GRAPH_MINS);
|
||||||
|
@ -246,6 +284,8 @@ RPCConsole::~RPCConsole()
|
||||||
{
|
{
|
||||||
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
|
GUIUtil::saveWindowGeometry("nRPCConsoleWindow", this);
|
||||||
Q_EMIT stopExecutor();
|
Q_EMIT stopExecutor();
|
||||||
|
RPCUnregisterTimerInterface(rpcTimerInterface);
|
||||||
|
delete rpcTimerInterface;
|
||||||
delete ui;
|
delete ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
class ClientModel;
|
class ClientModel;
|
||||||
class PlatformStyle;
|
class PlatformStyle;
|
||||||
|
class RPCTimerInterface;
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class RPCConsole;
|
class RPCConsole;
|
||||||
|
@ -108,6 +109,7 @@ private:
|
||||||
NodeId cachedNodeid;
|
NodeId cachedNodeid;
|
||||||
QMenu *contextMenu;
|
QMenu *contextMenu;
|
||||||
const PlatformStyle *platformStyle;
|
const PlatformStyle *platformStyle;
|
||||||
|
RPCTimerInterface *rpcTimerInterface;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_QT_RPCCONSOLE_H
|
#endif // BITCOIN_QT_RPCCONSOLE_H
|
||||||
|
|
|
@ -562,7 +562,7 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
|
||||||
deadlineTimers.erase(name);
|
deadlineTimers.erase(name);
|
||||||
RPCTimerInterface* timerInterface = timerInterfaces[0];
|
RPCTimerInterface* timerInterface = timerInterfaces[0];
|
||||||
LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
|
LogPrint("rpc", "queue run of timer %s in %i seconds (using %s)\n", name, nSeconds, timerInterface->Name());
|
||||||
deadlineTimers.insert(std::make_pair(name, timerInterface->NewTimer(func, nSeconds)));
|
deadlineTimers.insert(std::make_pair(name, timerInterface->NewTimer(func, nSeconds*1000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
const CRPCTable tableRPC;
|
const CRPCTable tableRPC;
|
||||||
|
|
|
@ -92,12 +92,12 @@ public:
|
||||||
/** Implementation name */
|
/** Implementation name */
|
||||||
virtual const char *Name() = 0;
|
virtual const char *Name() = 0;
|
||||||
/** Factory function for timers.
|
/** Factory function for timers.
|
||||||
* RPC will call the function to create a timer that will call func in *seconds* seconds.
|
* RPC will call the function to create a timer that will call func in *millis* milliseconds.
|
||||||
* @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
|
* @note As the RPC mechanism is backend-neutral, it can use different implementations of timers.
|
||||||
* This is needed to cope with the case in which there is no HTTP server, but
|
* This is needed to cope with the case in which there is no HTTP server, but
|
||||||
* only GUI RPC console, and to break the dependency of pcserver on httprpc.
|
* only GUI RPC console, and to break the dependency of pcserver on httprpc.
|
||||||
*/
|
*/
|
||||||
virtual RPCTimerBase* NewTimer(boost::function<void(void)>&, int64_t) = 0;
|
virtual RPCTimerBase* NewTimer(boost::function<void(void)>& func, int64_t millis) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Register factory function for timers */
|
/** Register factory function for timers */
|
||||||
|
|
Loading…
Reference in a new issue