1 module upromised.timer; 2 import deimos.libuv.uv : uv_timer_t, uv_handle_t, uv_loop_t, uv_timer_init, uv_timer_start, uv_timer_stop, uv_close, uv_timer_get_repeat; 3 import upromised.loop : Loop; 4 import upromised.promise : DelegatePromise, DelegatePromiseIterator, Promise, PromiseIterator; 5 import upromised.memory : getSelf, gcretain, gcrelease; 6 import upromised.uv : uvCheck; 7 import std.datetime : Duration; 8 import upromised : fatal; 9 10 uv_handle_t* handle(ref uv_timer_t self) nothrow { 11 return cast(uv_handle_t*)&self; 12 } 13 14 class Timer { 15 public: 16 uv_timer_t self; 17 DelegatePromise!void closePromise; 18 DelegatePromiseIterator!int startPromise; 19 20 this(Loop loop) { 21 this(cast(uv_loop_t*)loop.inner()); 22 } 23 24 this(uv_loop_t* ctx) { 25 uv_timer_init(ctx, &self).uvCheck(); 26 gcretain(this); 27 } 28 29 Promise!void close() nothrow { 30 if (closePromise !is null) return closePromise; 31 closePromise = new DelegatePromise!void; 32 uv_close(self.handle, (selfSelf) nothrow { 33 auto self = getSelf!Timer(selfSelf); 34 gcrelease(self); 35 self.closePromise.resolve(); 36 }); 37 return closePromise; 38 } 39 40 DelegatePromiseIterator!int start(Duration start, Duration repeat = Duration.init) nothrow { 41 import std.algorithm : swap; 42 43 assert(startPromise is null); 44 startPromise = new DelegatePromiseIterator!int; 45 auto r = startPromise; 46 int err = uv_timer_start(&self, (selfSelf) nothrow { 47 auto self = getSelf!Timer(selfSelf); 48 self.startPromise.resolve(0).then((cont) { 49 if (uv_timer_get_repeat(&self.self) == 0) { 50 self.startPromise.resolve(); 51 self.startPromise = null; 52 } else if (!cont) { 53 uv_timer_stop(&self.self); 54 self.startPromise = null; 55 } 56 }).nothrow_(); 57 }, start.total!"msecs", repeat.total!"msecs"); 58 if (err.uvCheck(startPromise)) { 59 startPromise = null; 60 } 61 return r; 62 } 63 64 static Promise!void once(uv_loop_t* ctx, Duration start = Duration.init) nothrow { 65 return Promise!void.resolved().then(() => new Timer(ctx)).then((timer) { 66 return timer.start(start).each((a){}).finall(() => timer.close()).then((){}); 67 }); 68 } 69 }