#include #include "ev_dispatch.h" #include "ev_http.h" /* ruby 1.9 compat */ #ifndef RSTRING_PTR #define RSTRING_PTR(str) RSTRING(str)->ptr #endif #ifndef RSTRING_LEN #define RSTRING_LEN(str) RSTRING(str)->len #endif /* * * Using ruby dispatch interface: * * require 'rev_dispatch' * * # create a new dispatch loop * d = Rev::Dispatch::Loop.new * * # start the event loop thread * * # send a dispatch http request and store a handle to the request * google_id = d.request("get", "http://www.google.com/") * * # do some processing and later on check for the response * while d.wait_for_response( google_id, 1, 0 ) * res = d.response_for( google_id ) * break if res * end * res = d.response_for( google_id ) unless res * * puts res.inspect # array of response values * * # sometime later you can stop the event loop * d.stop * * * You only get 1 background event loop, calling start multiple times will have no effect. * You typically don't need or want to stop the event loop after it's active. It will sit in the * background and happily wait for new requests using a minimal amount of cpu while waiting. * Everything in the background thread is written in C++ and has absolutely no hooks back into ruby. * The results of the work being processed in the background can be retrieved by ruby but that is it. */ static VALUE rb_Evdispatch; static VALUE rb_Loop; static VALUE Loop_start( VALUE self ) { EVD::Dispatch *d; Data_Get_Struct( self, EVD::Dispatch, d ); d->start(); return self; } static VALUE Loop_request_http( VALUE self, VALUE url ) { EVD::Dispatch *d; Data_Get_Struct( self, EVD::Dispatch, d ); EVD::request_t id = d->request( new EVD::HttpRequest( *d, RSTRING_PTR(url) ) ); return rb_int_new(id); } static VALUE Loop_wait_for_response( VALUE self, VALUE id, VALUE timeout_seconds, VALUE timeout_mseconds ) { EVD::Dispatch *d; EVD::Queue::POP_STATE rstate; EVD::request_t rid = FIX2LONG(id); Data_Get_Struct( self, EVD::Dispatch, d ); rstate = d->wait_for_response_by_id( rid, EVD::Timer(FIX2LONG(timeout_seconds), FIX2LONG(timeout_mseconds)) ); return rb_int_new(rstate); } static VALUE Loop_response_for( VALUE self, VALUE id ) { EVD::Dispatch *d; Data_Get_Struct( self, EVD::Dispatch, d ); EVD::Response *res = NULL; EVD::request_t rid = FIX2LONG(id); res = d->response_for( rid ); if( res ){ VALUE result = rb_hash_new(); rb_hash_aset( result, ID2SYM(rb_intern("name")), rb_str_new( res->name.c_str(), res->name.length() ) ); rb_hash_aset( result, ID2SYM(rb_intern("body")), rb_str_new( res->body.c_str(), res->body.length() ) ); rb_hash_aset( result, ID2SYM(rb_intern("id")), rb_int_new( res->id ) ); rb_hash_aset( result, ID2SYM(rb_intern("response_time")), rb_float_new( res->response_time ) ); delete res; return result; } return Qnil; } static VALUE Loop_stop( VALUE self ) { EVD::Dispatch *d; Data_Get_Struct( self, EVD::Dispatch, d ); d->stop(); return Qnil; } static void Loop_free( EVD::Dispatch *d ) { delete d; } static VALUE Loop_alloc(VALUE klass) { VALUE object; EVD::Dispatch *d = new EVD::Dispatch(); object = Data_Wrap_Struct( klass, NULL, Loop_free, d ); return object; } extern "C" void Init_revdispatch() { rb_Evdispatch = rb_define_module( "Evdispatch" ); rb_Loop = rb_define_class_under( rb_Evdispatch, "Loop", rb_cObject ); rb_define_alloc_func( rb_Loop, Loop_alloc ); rb_define_method( rb_Loop, "start", (VALUE (*)(...))Loop_start, 0 ); rb_define_method( rb_Loop, "request_http", (VALUE (*)(...))Loop_request_http, 1 ); rb_define_method( rb_Loop, "response_for", (VALUE (*)(...))Loop_response_for, 1 ); rb_define_method( rb_Loop, "wait_for_response", (VALUE (*)(...))Loop_wait_for_response, 3 ); rb_define_method( rb_Loop, "stop", (VALUE (*)(...))Loop_stop, 0 ); }