diff options
author | Tom Gilbert <tom@linuxbrit.co.uk> | 2005-07-27 16:32:32 +0000 |
---|---|---|
committer | Tom Gilbert <tom@linuxbrit.co.uk> | 2005-07-27 16:32:32 +0000 |
commit | 2a96c9198c1f6e13407d0999083f6ce5e0bc06fa (patch) | |
tree | b3b9247d275d9b554665bc22884104d266d2e757 /lib/rbot/timer.rb | |
parent | 21949774b91eaec6ecde4eaa8ad121e2c0a36b87 (diff) |
move rbot into lib - still rearranging for packaging/installation
Diffstat (limited to 'lib/rbot/timer.rb')
-rw-r--r-- | lib/rbot/timer.rb | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/lib/rbot/timer.rb b/lib/rbot/timer.rb new file mode 100644 index 00000000..64b060ba --- /dev/null +++ b/lib/rbot/timer.rb @@ -0,0 +1,123 @@ +module Timer + + # timer event, something to do and when/how often to do it + class Action + + # when this action is due next (updated by tick()) + attr_accessor :in + + # is this action blocked? if so it won't be run + attr_accessor :blocked + + # period:: how often (seconds) to run the action + # data:: optional data to pass to the proc + # once:: optional, if true, this action will be run once then removed + # func:: associate a block to be called to perform the action + # + # create a new action + def initialize(period, data=nil, once=false, &func) + @blocked = false + @period = period + @in = period + @func = func + @data = data + @once = once + end + + # run the action by calling its proc + def run + @in += @period + if(@data) + @func.call(@data) + else + @func.call + end + return @once + end + end + + # timer handler, manage multiple Action objects, calling them when required. + # The timer must be ticked by whatever controls it, i.e. regular calls to + # tick() at whatever granularity suits your application's needs. + # Alternatively you can call run(), and the timer will tick itself, but this + # blocks so you gotta do it in a thread (remember ruby's threads block on + # syscalls so that can suck). + class Timer + def initialize + @timers = Array.new + @handle = 0 + @lasttime = 0 + end + + # period:: how often (seconds) to run the action + # data:: optional data to pass to the action's proc + # func:: associate a block with add() to perform the action + # + # add an action to the timer + def add(period, data=nil, &func) + @handle += 1 + @timers[@handle] = Action.new(period, data, &func) + return @handle + end + + # period:: how often (seconds) to run the action + # data:: optional data to pass to the action's proc + # func:: associate a block with add() to perform the action + # + # add an action to the timer which will be run just once, after +period+ + def add_once(period, data=nil, &func) + @handle += 1 + @timers[@handle] = Action.new(period, data, true, &func) + return @handle + end + + # remove action with handle +handle+ from the timer + def remove(handle) + @timers.delete_at(handle) + end + + # block action with handle +handle+ + def block(handle) + @timers[handle].blocked = true + end + + # unblock action with handle +handle+ + def unblock(handle) + @timers[handle].blocked = false + end + + # you can call this when you know you're idle, or you can split off a + # thread and call the run() method to do it for you. + def tick + if(@lasttime != 0) + diff = (Time.now - @lasttime).to_f + @lasttime = Time.now + @timers.compact.each { |timer| + timer.in = timer.in - diff + } + @timers.compact.each { |timer| + if (!timer.blocked) + if(timer.in <= 0) + if(timer.run) + # run once + @timers.delete(timer) + end + end + end + } + else + # don't do anything on the first tick + @lasttime = Time.now + end + end + + # the timer will tick() itself. this blocks, so run it in a thread, and + # watch out for blocking syscalls + def run(granularity=0.1) + while(true) + sleep(granularity) + tick + end + end + end +end |