diff options
Diffstat (limited to 'player/mruby/events.mrb')
-rw-r--r-- | player/mruby/events.mrb | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/player/mruby/events.mrb b/player/mruby/events.mrb new file mode 100644 index 0000000000..ee00e7df71 --- /dev/null +++ b/player/mruby/events.mrb @@ -0,0 +1,221 @@ +module M + class Event < Struct.new(:id, :type, :error, :data) + %w(shutdown property-change).each do |n| + mname = n.gsub('-', '_') + '?' + define_method(mname) do + type == n + end + end + + def success? + error == "success" + end + end + + class EventLoop + attr_reader :timers, :properties, :events + + def initialize + @timers = Timers.new + @properties = PropertyObservers.new + @events = EventObservers.new + end + + def run + loop do + timers.fire + wait_time = timers.wait_time || 1e20 + event = M.wait_event(wait_time) + @properties.dispatch(event) + @events.dispatch(event) + break if event.shutdown? + end + end + end + + class Timers + def initialize + @timers = [] + end + + def fire + @timers.each(&:fire) + end + + def add(&block) + t = Timer.new(self, &block) + @timers.push(t) + t + end + + def delete(t) + @timers.delete(t) + end + + def wait_time + @timers.select(&:active?).map(&:wait_time).select{|t| t > 0}.min + end + end + + class Timer + attr_accessor :executions + + def initialize(timers, &block) + @timers = timers + @block = block + @active = false + self.executions = 0 + end + + def fire + return unless active? + return if wait_time > 0 + + self.executions += 1 + @block.call(self) + reschedule + end + + def cancel + @active = false + @timers.delete(self) + end + + def every(secs) + @interval = secs + once(secs) + end + + def once(secs) + @expire_time = now + secs + @active = true + end + + def wait_time + @expire_time - now + end + + def active? + @active + end + + private + def interval? + !! @interval + end + + def reschedule + every(@interval) if interval? + end + + def now + M.get_time + end + end + + class Observers + def initialize + @observers = {} + end + + def dispatch(event) + if handle?(event) and o = @observers[event_key(event)] + o.call(*observer_args(event)) + end + end + + def observe(k, &block) + id = get_key(k) + raw_observe(k, id).tap do |result| + if result.success? + @observers[id] = block + end + end + end + + def unobserve(id) + raw_unobserve(id).tap do |result| + if result.success? + @observers.delete(id) + end + end + end + + def handle?(event) + @observers.include?(event_key(event)) + end + end + + class EventObservers < Observers + def handle?(event) + super and event.id == 0 + end + + def observer_args(event) + [] + end + + def get_key(k) + k + end + + def event_key(event) + event.type + end + + def raw_observe(k, id) + M.request_event(k, true) + end + + def raw_unobserve(k) + M.request_event(k, false) + end + end + + class PropertyObservers < Observers + def get_key(k) + @_id ||= 1337 + @_id += 1 + end + + def observer_args(event) + [ event.data['value'] ] + end + + def event_key(event) + event.id + end + + def handle?(event) + super and event.id > 0 and event.property_change? + end + + def raw_observe(k, id) + M.observe_property_raw(id, k) + end + + def raw_unobserve(id) + M.unobserve_property_raw(id) + end + end + + def self.event_loop + @event_loop ||= EventLoop.new + end + + def self.properties + event_loop.properties + end + + def self.events + event_loop.events + end + + def self.timers + event_loop.timers + end + + def self.run + event_loop.run + end +end |