X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=lib%2Frbot%2Ftimer.rb;h=db0c6ea16bee0d89aefd0104832347551fee997c;hb=c4502412f30f69c1ffa053b160e01d3974b338aa;hp=03a4c91e268505750b91fc0979079c987e2d6ebd;hpb=6ad81c62702028559f2ccc2851842c871a2c79c4;p=user%2Fhenk%2Fcode%2Fruby%2Frbot.git diff --git a/lib/rbot/timer.rb b/lib/rbot/timer.rb index 03a4c91e..db0c6ea1 100644 --- a/lib/rbot/timer.rb +++ b/lib/rbot/timer.rb @@ -2,10 +2,10 @@ 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_reader :in - + # is this action blocked? if so it won't be run attr_accessor :blocked @@ -13,7 +13,7 @@ module Timer # 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 @@ -31,7 +31,7 @@ module Timer @last_tick = Time.new end - def inspect + def inspect "#<#{self.class}:#{@period}s:#{@once ? 'once' : 'repeat'}>" end @@ -45,19 +45,31 @@ module Timer # really short duration timers can overrun and leave @in negative, # for these we set @in to @period @in = @period if @in <= 0 - if(@data) - @func.call(@data) - else - @func.call + begin + if(@data) + @func.call(@data) + else + @func.call + end + rescue Exception => e + error "Timer action #{self.inspect} with function #{@func.inspect} failed!" + error e.pretty_inspect + # TODO maybe we want to block this Action? end return @once end + + # reschedule the Action to change its period + def reschedule(new_period) + @period = new_period + @in = new_period + 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 spawn a thread and # tick itself, intelligently shutting down the thread if there are no # pending actions. @@ -71,11 +83,11 @@ module Timer @thread = false @next_action_time = 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) debug "adding timer, period #{period}" @@ -88,7 +100,7 @@ module Timer # period:: how long (seconds) until the action is run # 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) debug "adding one-off timer, period #{period}" @@ -102,20 +114,28 @@ module Timer def remove(handle) @timers.delete(handle) end - + # block action with handle +handle+ def block(handle) + raise "no such timer #{handle}" unless @timers[handle] @timers[handle].blocked = true end # unblock action with handle +handle+ def unblock(handle) + raise "no such timer #{handle}" unless @timers[handle] @timers[handle].blocked = false end + # reschedule action with handle +handle+ to change its period + def reschedule(handle, period) + raise "no such timer #{handle}" unless @timers[handle] + @timers[handle].reschedule(period) + 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 + def tick if(@lasttime == 0) # don't do anything on the first tick @lasttime = Time.now @@ -173,9 +193,9 @@ module Timer @should_be_running = false stop_thread end - + private - + def start_on_add if running? stop_thread @@ -184,12 +204,12 @@ module Timer start_thread end end - + def stop_thread return unless running? @thread.kill end - + def start_thread return if running? @thread = Thread.new do