#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 = Evdispatch::Loop.new * * # start the event loop thread * * # send a dispatch http request and store a handle to the request * google_id = d.request_http("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[:body] * * # 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. * * the request method can be used passing it options will set specific libcurl options * */ 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); } #define SET_LONG_VAL(name)\ {\ VALUE obj = rb_hash_aref( options, ID2SYM(rb_intern(name)) ); \ if( !NIL_P(obj) ) {\ snprintf( VALUE_BUFFER, VALUE_BUFFER_SIZE, "%d", FIX2LONG(obj) );\ req->set_opt(name, VALUE_BUFFER);\ }\ } #define SET_STR_VAL(name)\ {\ VALUE obj = rb_hash_aref( options, ID2SYM(rb_intern(name)) ); \ if( !NIL_P(obj) ) {\ req->set_opt(name, RSTRING_PTR(obj));\ }\ } static VALUE Loop_request( VALUE self, VALUE url, VALUE options ) { EVD::Dispatch *d; const int VALUE_BUFFER_SIZE = 1024; char VALUE_BUFFER[VALUE_BUFFER_SIZE]; Data_Get_Struct( self, EVD::Dispatch, d ); EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url) ); // check for some specific options SET_LONG_VAL("port"); SET_STR_VAL("autoreferer"); SET_LONG_VAL("followlocation"); SET_LONG_VAL("maxredirs"); SET_STR_VAL("referer"); SET_STR_VAL("useragent"); SET_STR_VAL("cookie"); return rb_int_new( d->request(req) ); } 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::HttpResponse *res = NULL; EVD::request_t rid = FIX2LONG(id); res = (EVD::HttpResponse*)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 ) ); rb_hash_aset( result, ID2SYM(rb_intern("header")), rb_str_new( res->m_header.c_str(), res->m_header.length() ) ); 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 ); // setup the Loop object 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, "request", (VALUE (*)(...))Loop_request, 2 ); 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 ); }