#include "node.h" #include "node_timer.h" #include using namespace v8; class Timer { public: Timer(Handle callback, int argc, Handle argv[], ev_tstamp after, ev_tstamp repeat); ~Timer(); Local CreateTimeoutID (); void CallCallback (); private: ev_timer watcher; Persistent timeoutID; Persistent callback; int argc; Persistent argv[]; }; static void onTimeout (struct ev_loop *loop, ev_timer *watcher, int revents) { Timer *timer = static_cast(watcher->data); timer->CallCallback(); // use ev_is_active instead? if(watcher->repeat == 0.) delete timer; } Timer::Timer (Handle _callback, int _argc, Handle _argv[], ev_tstamp after, ev_tstamp repeat) { HandleScope scope; callback = Persistent::New(_callback); argc = _argc; ev_timer_init (&watcher, onTimeout, after, repeat); watcher.data = this; ev_timer_start (node_loop(), &watcher); } Timer::~Timer () { ev_timer_stop (node_loop(), &watcher); callback.Dispose(); timeoutID.Dispose(); timeoutID.Clear(); } void Timer::CallCallback () { HandleScope scope; TryCatch try_catch; callback->Call (Context::GetCurrent()->Global(), argc, argv); if(try_catch.HasCaught()) node_fatal_exception(try_catch); } Local Timer::CreateTimeoutID () { HandleScope scope; Local timeoutID_local = External::New(this); timeoutID = Persistent::New(timeoutID_local); return scope.Close(timeoutID_local); } static Timer * UnwrapTimeoutID (Handle timeoutID) { HandleScope scope; Timer *timer = static_cast(timeoutID->Value()); return timer; } // timeoutID = setTimeout(func, delay, [param1, param2, ...]); // timeoutID = setTimeout(code, delay); // // * timeoutID is the ID of the timeout, which can be used with // clearTimeout. // // * func is the function you want to execute after delay milliseconds. // // * code in the alternate syntax, is a string of code you want to execute // after delay milliseconds. (not recommended) // // * delay is the number of milliseconds (thousandths of a second) that the // function call should be delayed by. static Handle setTimeout(const Arguments& args) { if (args.Length() < 2) return Undefined(); HandleScope scope; Local callback = Local::Cast(args[0]); uint32_t delay = args[1]->Uint32Value(); ev_tstamp after = (double)delay / 1000.0; if (args.Length() > 2) assert(0 && "extra params to setTimeout not yet implemented."); int argc = 0; Handle argv[] = {}; /* int argc = args.Length() - 2; Handle argv[] = new Handle[argc]; // the rest of the arguments, if any arg parameters for the callback for(int i = 2; i < args.Length(); i++) argv[i - 2] = args[i]; */ Timer *timer = new Timer(callback, argc, argv, after, 0.0); Local timeoutID = timer->CreateTimeoutID(); return scope.Close(timeoutID); } // clearTimeout(timeoutID) static Handle clearTimeout ( const Arguments& args ) { if (args.Length() < 1) return Undefined(); Handle timeoutID = Handle::Cast(args[0]); Timer *timer = UnwrapTimeoutID(timeoutID); delete timer; return Undefined(); } // intervalID = setInterval(func, delay[, param1, param2, ...]); // intervalID = setInterval(code, delay); // // where // // * intervalID is a unique interval ID you can pass to clearInterval(). // // * func is the function you want to be called repeatedly. // // * code in the alternate syntax, is a string of code you want to be executed // repeatedly. // // * delay is the number of milliseconds (thousandths of a second) that the // setInterval() function should wait before each call to func. static Handle setInterval ( const Arguments& args ) { if (args.Length() < 2) return Undefined(); HandleScope scope; Local callback = Local::Cast(args[0]); uint32_t delay = args[1]->Uint32Value(); ev_tstamp after = (double)delay / 1000.0; if (args.Length() > 2) assert(0 && "extra params to setInterval not yet implemented."); int argc = 0; Handle argv[] = {}; Timer *timer = new Timer(callback, argc, argv, after, after); Local timeoutID = timer->CreateTimeoutID(); return scope.Close(timeoutID); } void Init_timer (Handle target) { HandleScope scope; target->Set ( String::New("setTimeout") , FunctionTemplate::New(setTimeout)->GetFunction() ); target->Set ( String::New("clearTimeout") , FunctionTemplate::New(clearTimeout)->GetFunction() ); target->Set ( String::New("setInterval") , FunctionTemplate::New(setInterval)->GetFunction() ); target->Set ( String::New("clearInterval") , FunctionTemplate::New(clearTimeout)->GetFunction() ); }