Skip to content

Commit

Permalink
Implement RPCTimerHandler for Qt RPC console
Browse files Browse the repository at this point in the history
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.

Zcash: QT changes ommitted
  • Loading branch information
laanwj authored and Jack Grigg committed Mar 23, 2017
1 parent afd64f7 commit 858afa1
Show file tree
Hide file tree
Showing 5 changed files with 25 additions and 50 deletions.
22 changes: 7 additions & 15 deletions src/httprpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,24 +19,16 @@
class HTTPRPCTimer : public RPCTimerBase
{
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);
}
private:
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
Expand All @@ -49,9 +41,9 @@ class HTTPRPCTimerInterface : public RPCTimerInterface
{
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:
struct event_base* base;
Expand Down
33 changes: 8 additions & 25 deletions src/httpserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -412,18 +412,15 @@ struct event_base* EventBase()

static void httpevent_callback_fn(evutil_socket_t, short, void* data)
{
// Static handler simply passes through execution flow to _handle method
((HTTPEvent*)data)->_handle();
// Static handler: simply call inner handler
HTTPEvent *self = ((HTTPEvent*)data);
self->handler();
if (self->deleteWhenTriggered)
delete self;
}

void HTTPEvent::_handle()
{
(*handler)();
if (deleteWhenTriggered)
delete this;
}

HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, HTTPClosure* handler) : deleteWhenTriggered(deleteWhenTriggered), handler(handler)
HTTPEvent::HTTPEvent(struct event_base* base, bool deleteWhenTriggered, const boost::function<void(void)>& handler):
deleteWhenTriggered(deleteWhenTriggered), handler(handler)
{
ev = event_new(base, -1, 0, httpevent_callback_fn, this);
assert(ev);
Expand Down Expand Up @@ -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,
* 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)
{
assert(!replySent && req);
Expand All @@ -518,7 +501,7 @@ void HTTPRequest::WriteReply(int nStatus, const std::string& strReply)
assert(evb);
evbuffer_add(evb, strReply.data(), strReply.size());
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);
replySent = true;
req = 0; // transferred back to main thread
Expand Down
14 changes: 7 additions & 7 deletions src/httpserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,22 +117,22 @@ class HTTPClosure
class HTTPEvent
{
public:
/** Create a new event */
HTTPEvent(struct event_base* base, bool deleteWhenTriggered, HTTPClosure* handler);
/** Create a new event.
* 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();

/** Trigger the event. If tv is 0, trigger it immediately. Otherwise trigger it after
* the given time has elapsed.
*/
void trigger(struct timeval* tv);

/** Internal function for handling, do not call directly */
void _handle();

private:
bool deleteWhenTriggered;
boost::function<void(void)> handler;
private:
struct event* ev;
boost::scoped_ptr<HTTPClosure> handler;
};

#endif // BITCOIN_HTTPSERVER_H
2 changes: 1 addition & 1 deletion src/rpcserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ void RPCRunLater(const std::string& name, boost::function<void(void)> func, int6
deadlineTimers.erase(name);
RPCTimerInterface* timerInterface = timerInterfaces[0];
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;
Expand Down
4 changes: 2 additions & 2 deletions src/rpcserver.h
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ class RPCTimerInterface
/** Implementation name */
virtual const char *Name() = 0;
/** 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.
* 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.
*/
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 */
Expand Down

0 comments on commit 858afa1

Please sign in to comment.