aboutsummaryrefslogtreecommitdiffstats
path: root/tools/python/xen/xend/EventServer.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/python/xen/xend/EventServer.py')
-rw-r--r--tools/python/xen/xend/EventServer.py215
1 files changed, 215 insertions, 0 deletions
diff --git a/tools/python/xen/xend/EventServer.py b/tools/python/xen/xend/EventServer.py
new file mode 100644
index 0000000000..20c567ada7
--- /dev/null
+++ b/tools/python/xen/xend/EventServer.py
@@ -0,0 +1,215 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+"""Simple publish/subscribe event server.
+
+"""
+import string
+
+from twisted.internet import reactor
+
+# subscribe a.b.c h: map a.b.c -> h
+# subscribe a.b.* h: map a.b.* -> h
+# subscribe a.b.? h: map a.b.? -> h
+#
+# for event a.b.c.d:
+#
+# lookup a.b.c.d, call handlers
+#
+# lookup a.b.c.?, call handlers
+#
+# lookup a.b.c.d.*, call handlers
+# lookup a.b.c.*, call handlers
+# lookup a.b.*, call handlers
+# lookup a.*, call handlers
+# lookup *, call handlers
+
+# a.b.c.d = (a b c d)
+# a.b.c.? = (a b c _)
+# a.b.c.* = (a b c . _)
+
+class EventServer:
+
+ DOT = '.'
+ QUERY = '?'
+ DOT_QUERY = DOT + QUERY
+ STAR = '*'
+ DOT_STAR = DOT + STAR
+
+ def __init__(self, run=0):
+ self.handlers = {}
+ self.run = run
+ self.queue = []
+
+ def start(self):
+ """Enable event handling. Sends any queued events.
+ """
+ self.run = 1
+ for (e,v) in self.queue:
+ self.inject(e, v)
+ self.queue = []
+
+ def stop(self):
+ """Suspend event handling. Events injected while suspended
+ are queued until we are started again.
+ """
+ self.run = 0
+
+ def subscribe(self, event, handler):
+ """Subscribe to an event. For example 'a.b.c.d'.
+ A subcription like 'a.b.c.?' ending in '?' matches any value
+ for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
+ any event type with the same prefix, 'a.b.c' in this case.
+
+ event event name
+ handler event handler fn(event, val)
+ """
+ hl = self.handlers.get(event)
+ if hl is None:
+ self.handlers[event] = [handler]
+ else:
+ hl.append(handler)
+
+ def unsubscribe_all(self, event=None):
+ """Unsubscribe all handlers for a given event, or all handlers.
+
+ event event (optional)
+ """
+ if event == None:
+ self.handlers.clear()
+ elif event in self.handlers:
+ del self.handlers[event]
+
+ def unsubscribe(self, event, handler):
+ """Unsubscribe a given event and handler.
+
+ event event
+ handler handler
+ """
+ hl = self.handlers.get(event)
+ if hl is None:
+ return
+ if handler in hl:
+ hl.remove(handler)
+
+ def inject(self, event, val, async=1):
+ """Inject an event. Handlers for it are called if running, otherwise
+ it is queued.
+
+ event event type
+ val event value
+ """
+ if self.run:
+ if async:
+ reactor.callLater(0, self.call_handlers, event, val)
+ else:
+ self.notify_handlers(event, val)
+ else:
+ self.queue.append( (event, val) )
+
+ def call_handlers(self, event, val):
+ """Internal method to call event handlers.
+ """
+ #print ">event", event, val
+ self.call_event_handlers(event, event, val)
+ self.call_query_handlers(event, val)
+ self.call_star_handlers(event, val)
+
+ def call_event_handlers(self, key, event, val):
+ """Call the handlers for an event.
+ It is safe for handlers to subscribe or unsubscribe.
+
+ key key for handler list
+ event event type
+ val event value
+ """
+ hl = self.handlers.get(key)
+ if hl is None:
+ return
+ # Copy the handler list so that handlers can call
+ # subscribe/unsubscribe safely - python list iteration
+ # is not safe against list modification.
+ for h in hl[:]:
+ try:
+ h(event, val)
+ except:
+ pass
+
+ def call_query_handlers(self, event, val):
+ """Call regex handlers for events matching 'event' that end in '?'.
+
+ event event type
+ val event value
+ """
+ dot_idx = event.rfind(self.DOT)
+ if dot_idx == -1:
+ self.call_event_handlers(self.QUERY, event, val)
+ else:
+ event_query = event[0:dot_idx] + self.DOT_QUERY
+ self.call_event_handlers(event_query, event, val)
+
+ def call_star_handlers(self, event, val):
+ """Call regex handlers for events matching 'event' that end in '*'.
+
+ event event type
+ val event value
+ """
+ etype = string.split(event, self.DOT)
+ for i in range(len(etype), 0, -1):
+ event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
+ self.call_event_handlers(event_star, event, val)
+ self.call_event_handlers(self.STAR, event, val)
+
+def instance():
+ global inst
+ try:
+ inst
+ except:
+ inst = EventServer()
+ inst.start()
+ return inst
+
+def main():
+ def sys_star(event, val):
+ print 'sys_star', event, val
+
+ def sys_foo(event, val):
+ print 'sys_foo', event, val
+ s.unsubscribe('sys.foo', sys_foo)
+
+ def sys_foo2(event, val):
+ print 'sys_foo2', event, val
+
+ def sys_bar(event, val):
+ print 'sys_bar', event, val
+
+ def sys_foo_bar(event, val):
+ print 'sys_foo_bar', event, val
+
+ def foo_bar(event, val):
+ print 'foo_bar', event, val
+
+ s = EventServer()
+ s.start()
+ s.subscribe('sys.*', sys_star)
+ s.subscribe('sys.foo', sys_foo)
+ s.subscribe('sys.foo', sys_foo2)
+ s.subscribe('sys.bar', sys_bar)
+ s.subscribe('sys.foo.bar', sys_foo_bar)
+ s.subscribe('foo.bar', foo_bar)
+ s.inject('sys.foo', 'hello')
+ print
+ s.inject('sys.bar', 'hello again')
+ print
+ s.inject('sys.foo.bar', 'hello again')
+ print
+ s.inject('foo.bar', 'hello again')
+ print
+ s.inject('foo', 'hello again')
+ print
+ s.start()
+ s.unsubscribe('sys.*', sys_star)
+ s.unsubscribe_all('sys.*')
+ s.inject('sys.foo', 'hello')
+
+if __name__ == "__main__":
+ main()
+