]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blobdiff - lib/rbot/timer.rb
timer: tick when rescheduling
[user/henk/code/ruby/rbot.git] / lib / rbot / timer.rb
index 03a4c91e268505750b91fc0979079c987e2d6ebd..bebe41f2fd589ba2fd9ccd41db8d354eb7dde0f2 100644 (file)
@@ -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,29 @@ 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)
+      tick
+    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 +194,9 @@ module Timer
       @should_be_running = false
       stop_thread
     end
-    
+
     private
-    
+
     def start_on_add
       if running?
         stop_thread
@@ -184,12 +205,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