Ability to schedule HTTP client work on service run-loop.
service.schedule( Request request, const function< void ( Request, Response ) >& callback );
Comment from the peanut gallery: This is a great idea, although not quite enough for my use case. My application needs to perform asynchronous I/O on pipes and files to collect data for HTTP replies, and also run timed events in parallel -- so rather than go multithreaded or export the asio APIs one at a time, I ended up just hacking in a way to supply my own asio::io_service for restbed::Service to use. I can definitely see the appeal of a 'lite' mode where there's no exposed dependencies on non-std libraries, but (in my opinion) integrating with the rest of the asio framework really unlocks the full potential of restbed.
Could you supply a code sample showing your core use case?
I'll see if we have anything in the pipeline that might alleviate your "hack" ;)
Sure - I'll see if I can put together an illustrative example.
OK, I've put together an example at https://github.com/willmmiles/restbed/tree/external_asio called 'cgi'. It's a partial implementation of a CGI-like interface whereby an external program is called and the results are streamed back to the client. ASIO is used to allow parallel operation processing. As written, the example should take the POST data, feed it in to 'sort', and return the results to the client.
I integrated it into the build tree even though the code isn't of the same quality because it seemed like the simplest way to make sure you could build it easily. Note that this prototype uses posix_spawn, so it needs to be run on a UNIX-like system.
My specific application does something similar, although not exactly the same. I'm putting together a network front-end for a package management system, so I need to be able to collect the output of package's shell install scripts and stream it back to a client in real time. This kind of solution lets me achieve this without resorting to threading or polling.
Thanks for this, please allow us some time to review your example.
@willmmiles Given the fact that ASIO is getting main streamed into an upcoming C++ Standard. I'd like to propose the following.
shared_ptr< asio::io_service > Service::get_runloop( void ) const;
void Service::set_runloop( const shared_ptr< asio::io_service >& );
Do you have any thoughts?
FYI: We've been reluctant to expose our dependencies to 3rd-parties. However, as stated ASIO is getting mainstreamed.
Hm, in terms of implementation details, I'd be somewhat wary of a the set_runloop() call -- you'd have to carefully manage where this is legal, because IIRC a reference to the asio::io_service class is captured in all of the asio::*::socket() classes when constructed (and other places, possibly), and that reference can't be changed after construction. I think it might be better to optionally accept a shared_ptrasio::io_service object during restbed::Service construction instead; then you don't have to worry about managing object scope.
Re dependencies -- from my chair, the deep question is how you want to think of the relationship between restbed and ASIO. Is it a dependency - an implementation detail irrelevant to a potential user? Or is ASIO a foundation - an environment upon which restbed may be plugged in to offer some powerful new abstractions? My $0.02 would be that since restbed's core approach seems to be strongly related to ASIO concepts, I think it might make more sense to treat ASIO as a foundational component supplied by the environment, rather than a dependency best kept hidden.
Restbed currently has no support for run-time modifications. You would be restricted to calling set_runloop prior to Service::start.
Discussions have been conducted on whether ASIO is the correct choice. We are working towards an architecture where you would supply a Runloop epoll, select, LibEvent, LibUV, or another approach.
vision
auto service = make_shared< Service >( );
service->set_runloop( EPollInstance );
service->add_application_layer( HTTP1Instance );
service->add_application_layer( HTTP2Instance );
service->add_application_layer( SPDYInstance );
service->set_network_layer( TCPInstance );
//service->set_network_layer( RS232Instance);
//service->set_network_layer( USBInstance);
service.start( settings );
auto service = make_shared< Service >( settings, runloop );
auto runloop = service->get_runloop( );
...
auto runloop = session->get_runloop( );