Commit 9dc3d9bf authored by Timothy Stack's avatar Timothy Stack

Python binding for the event system

parent eee747f7
......@@ -1237,6 +1237,7 @@ else
event/tbgen/GNUmakefile event/tbgen/tevd.restart \
event/example/GNUmakefile event/example/tbsend.pl \
event/example/tbrecv.pl event/example/tbsend-short.pl \
event/example/tbsend.py event/example/tbrecv.py \
event/example/eventdebug.pl \
event/trafgen/GNUmakefile \
event/proxy/GNUmakefile \
......
......@@ -352,6 +352,7 @@ else
event/tbgen/GNUmakefile event/tbgen/tevd.restart \
event/example/GNUmakefile event/example/tbsend.pl \
event/example/tbrecv.pl event/example/tbsend-short.pl \
event/example/tbsend.py event/example/tbrecv.py \
event/example/eventdebug.pl \
event/trafgen/GNUmakefile \
event/proxy/GNUmakefile \
......
#
# EMULAB-COPYRIGHT
# Copyright (c) 2004 University of Utah and the Flux Group.
# All rights reserved.
#
This is the documentation for the Python API to the event system...
The Python version of the API is related to the Perl version in that
they both use the same SWIG infrastructure. The difference is in the
presentations, where the Perl API is basically the same as the C
version, the Python API provides a couple of wrapper classes to make
things easier.
CLASS OVERVIEW
The classes are contained in the "tbevent" module, currently, there
are two that are of any consequence. A brief overview of the classes
follows, consult the tbevent.py.tail source for more information.
EventClient - The base class for event system clients. Subscribers
should create a subclass and override the "handle_event" method to
process incoming events. Publishers do not need to create a
subclass, the base class already provides the necessary
functionality.
NotificationWrapper - A wrapper for event_notification structures,
contains common setter and getter methods for accessing the
structure.
EXAMPLES
See the tbsend.py and tbrecv.py files in the examples directory.
......@@ -4,7 +4,7 @@ OBJDIR = ../..
SUBDIR = event/example
SYSTEM := $(shell uname -s)
PROGRAMS = tbrecv tbsend eventdebug.pl
PROGRAMS = tbrecv tbsend tbrecv.py tbsend.py eventdebug.pl
include $(OBJDIR)/Makeconf
......
#! /usr/local/bin/python
import sys
import time
import getopt
sys.path.append("@prefix@/lib")
from tbevent import *
# Usage message
usage = """Example python testbed event receiver.
Usage: tbrecv.py [-h] [-s server] [-p port]
Optional arguments:
-h Print this message.
-s name The host name where the elvin event server is located.
(Default: boss)
-p port The port the elvin event server is listening on.
Example output:
Event: 1087828041:50467 * * * * TBEXAMPLE * FOO
"""
# Default values
server = "boss"
port = ""
# Process command line arguments
try:
opts, args = getopt.getopt(sys.argv[1:],
"hs:p:",
[ "help",
"server=",
"port=" ])
for opt, val in opts:
if opt in ("-h", "--help"):
sys.stderr.write(usage)
sys.exit()
pass
elif opt in ("-s", "--server"):
server = val
pass
elif opt in ("-p", "--port"):
port = val
pass
else:
sys.stderr.write("Unhandled option: " + opt + "\n")
pass
pass
pass
except getopt.error:
sys.stderr.write(usage)
sys.exit(2)
pass
#
# Python clients are built around the EventClient class with the "handle_event"
# method being used to process individual events.
#
class MyClient(EventClient):
def handle_event(self, event):
"""
Our event handler, just print out the event.
"""
#
# The "event" object is a NotificationWrapper and has all of the setter
# and getter methods.
#
print ("Event: "
+ `time.time()`
+ " "
+ event.getSite()
+ " "
+ event.getExpt()
+ " "
+ event.getGroup()
+ " "
+ event.getHost()
+ " "
+ event.getObjType()
+ " "
+ event.getObjName()
+ " "
+ event.getEventType())
return
pass
#
# Allocate and initialize an address tuple like any other python object, there
# is no need to use address_tuple_alloc().
#
at = address_tuple()
at.host = ADDRESSTUPLE_ALL
at.objtype = "TBEXAMPLE"
# Construct our client and
mc = MyClient(server=server, port=port)
# ... subscribe to the address.
mc.subscribe(at)
# Start receiving events...
mc.run()
#! /usr/local/bin/python
import sys
import getopt
sys.path.append("@prefix@/lib")
from tbevent import *
# Usage message
usage = """Example python testbed event sender.
Usage: tbsend.py [-h] [-s server] [-p port] <event>
Optional arguments:
-h Print this message.
-s name The host name where the elvin event server is located.
(Default: boss)
-p port The port the elvin event server is listening on.
Example:
$ tbsend.py FOO
"""
# Default values
server = "boss"
port = ""
# Process command line arguments
try:
opts, args = getopt.getopt(sys.argv[1:],
"hs:p:",
[ "help",
"server=",
"port=" ])
for opt, val in opts:
if opt in ("-h", "--help"):
sys.stderr.write(usage)
sys.exit()
pass
elif opt in ("-s", "--server"):
server = val
pass
elif opt in ("-p", "--port"):
port = val
pass
else:
sys.stderr.write("Unhandled option: " + opt + "\n")
pass
pass
if len(args) == 0:
sys.stderr.write(usage)
sys.exit(2)
pass
pass
except getopt.error:
sys.stderr.write(usage)
sys.exit(2)
pass
#
# Allocate and initialize an address tuple like any other python object, there
# is no need to use address_tuple_alloc().
#
at = address_tuple()
at.host = ADDRESSTUPLE_ALL
at.objtype = "TBEXAMPLE"
at.eventtype = sys.argv[1].upper() # XXX Uppercase everything...
# Construct a regular client,
ec = EventClient(server=server, port=port)
# ... create our notification, and
en = ec.create_notification(at)
# ... send it off.
ec.notify(en)
......@@ -14,7 +14,7 @@ include $(OBJDIR)/Makeconf
SYSTEM := $(shell uname -s)
PROGRAMS = libevent.a
ifneq ($(SYSTEM),Linux)
PROGRAMS += libevent_r.a event.so
PROGRAMS += libevent_r.a event.so _tbevent.so
endif
all: $(PROGRAMS)
......@@ -32,6 +32,7 @@ ifeq ($(SYSTEM),Linux)
PCORE = -I/usr/lib/perl5/5.6.1/i386-linux/CORE
else
PCORE = -I/usr/libdata/perl/5.00503/mach/CORE
PYCORE = -I/usr/local/include/python2.3
endif
OBJS = event.o util.o
......@@ -61,7 +62,7 @@ util.o: util.c
#
#
# SWIG has some horribly annyonying behavior and bugs that we have to work
# SWIG has some horribly annoying behavior and bugs that we have to work
# around, so we normally check the SWIG-generated code into CVS. This is a
# maintainer target for regenerating the SWIG wrappers - see README for full
# instructions
......@@ -74,18 +75,42 @@ swig-wrappers: event.i event.c event.pm.tail
event_wrap.o: $(SRCDIR)/event_wrap.c
$(CC) -c $(CFLAGS_NOWARN) $(PCORE) $<
#
# Note: The python version of the wrappers do not seem to be afflicted by the
# same problems as the perl one.
#
swig-pywrappers: event.i event.c tbevent.py.tail
swig -python -I$(SRCDIR) -o $(SRCDIR)/event_wrap_py.c -module tbevent \
$(SRCDIR)/event.i
cat $(SRCDIR)/tbevent.py.tail >> $(SRCDIR)/tbevent.py
touch $@
$(SRCDIR)/event_wrap_py.c: swig-pywrappers
event_wrap_py.o: $(SRCDIR)/event_wrap_py.c
$(CC) -c $(CFLAGS_NOWARN) $(PYCORE) $<
event.so: event.o event_wrap.o util.o
ld -shared $^ `elvin-config --libs vin4c` -lcrypto -o event.so
LIB_STUFF = event.pm event.so
_tbevent.so: event.o event_wrap_py.o util.o
ld -shared $^ `elvin-config --libs vin4c` -lcrypto -o $@
LIB_STUFF = event.pm event.so tbevent.py _tbevent.so
install: $(addprefix $(INSTALL_LIBDIR)/, $(LIB_STUFF))
control-install: install
client-install:
#
# XXX Fix the python install location.
#
client-install:
$(INSTALL_PROGRAM) $(SRCDIR)/event.pm $(DESTDIR)$(CLIENT_BINDIR)/event.pm
$(INSTALL_PROGRAM) event.so $(DESTDIR)$(CLIENT_BINDIR)/event.so
$(INSTALL_PROGRAM) $(SRCDIR)/tbevent.py \
$(DESTDIR)$(CLIENT_BINDIR)/tbevent.py
$(INSTALL_PROGRAM) _tbevent.so $(DESTDIR)$(CLIENT_BINDIR)/_tbevent.so
clean:
/bin/rm -f *.o libevent.a libevent_r.a *.so
/bin/rm -f *.o libevent.a libevent_r.a *.so *.py swig-pywrappers
/*
* EMULAB-COPYRIGHT
* Copyright (c) 2000-2003 University of Utah and the Flux Group.
* Copyright (c) 2000-2004 University of Utah and the Flux Group.
* All rights reserved.
*/
......@@ -58,7 +58,7 @@ typedef elvin_subscription_t event_subscription_t;
* A tuple defines the target of the event, or if you are a subscriber,
* what events you want to subscribe to.
*/
typedef struct {
typedef struct _address_tuple {
char *site; /* Which Emulab site. God only */
char *expt; /* Project and experiment IDs */
char *group; /* User defined group of nodes */
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
# -*- python -*-
#
# CODE PAST THIS POINT WAS NOT AUTOMATICALLY GENERATED BY SWIG
#
# For now, this has to get cat'ed onto the end of tbevent.py, since it
# doesn't seem possible to get SWIG to just pass it through into the
# output file
#
import time
class NotificationWrapper:
"""
Wrapper class for event_notification structures. Mostly just adds setter
and getter methods.
"""
def __init__(self, handle, notification):
"""
Construct a NotificationWrapper that wraps the given objects.
@param handle The event_handle used to create notification.
@param notification The event_notification structure to wrap.
"""
self.handle = handle
self.notification = notification
return
def __del__(self):
"""
Deconstruct the object by free'ing the wrapped notification.
"""
event_notification_free(self.handle, self.notification)
return
# For the rest of these, consult the C header file, event.h.
def getSite(self):
return event_notification_get_site(self.handle, self.notification)
def getExpt(self):
return event_notification_get_expt(self.handle, self.notification)
def getGroup(self):
return event_notification_get_group(self.handle, self.notification)
def getHost(self):
return event_notification_get_host(self.handle, self.notification)
def getObjType(self):
return event_notification_get_objtype(self.handle, self.notification)
def getObjName(self):
return event_notification_get_objname(self.handle, self.notification)
def getEventType(self):
return event_notification_get_eventtype(self.handle, self.notification)
def getArguments(self):
return event_notification_get_arguments(self.handle, self.notification)
def setArguments(self, args):
return event_notification_set_arguments(self.handle,
self.notification,
args)
def getSender(self):
return event_notification_get_sender(self.handle, self.notification)
def setSender(self, sender):
return event_notification_set_sender(self.handle,
self.notification,
sender)
pass
class CallbackIterator:
"""
Python iterator for the callback list created by the SWIG stubs.
"""
def __init__(self, handle):
"""
Construct an iterator with the given arguments.
@param handle The event_handle being polled.
"""
self.last = None
self.handle = handle
return
def __del__(self):
"""
Deconstruct the iterator.
"""
if self.last:
free_callback_data(self.last)
self.last = None
pass
return
def __iter__(self):
return self
def next(self):
"""
Return the next object in the sequence or raise StopIteration if there
are no more. The returned object is a wrapped notification.
"""
if self.last:
free_callback_data(self.last)
self.last = None
pass
self.last = dequeue_callback_data()
if not self.last:
raise StopIteration
return NotificationWrapper(self.handle,
self.last.callback_notification)
pass
class EventClient:
"""
Event client class, mostly just wraps the SWIG'd versions of the functions.
"""
def __init__(self, server=None, port=None, url=None):
"""
Construct an EventClient object.
@param url The server name in url'ish form (e.g. elvin://boss)
@param server The name of the server.
@param port The server port number.
"""
if url:
if not url.startswith("elvin:"):
raise ValueError, "malformed url: " + url
pass
else:
if not server:
raise ValueError, "url or server must be given"
url = "elvin://" + server
if port and len(port) > 0:
url = url + ":" + port
pass
self.handle = event_register(url, 0)
return
def __del__(self):
"""
Deconstruct this object by disconnecting from the server.
"""
event_unregister(self.handle)
self.handle = None
return
def _callbacks(self):
"""
Return an iterator that traverses the list of callbacks generated by
the SWIG wrapper.
"""
return CallbackIterator(self.handle)
def handle_event(self, ev):
"""
Default implementation of the event handling method. Should be
overridden by subclasses.
"""
return
def subscribe(self, tuple):
"""
Subscribe to some events.
@param tuple The address tuple describing the subscription.
"""
return stub_event_subscribe(self.handle, tuple.this)
def create_notification(self, tuple):
"""
@return A notification that is bound to this client.
"""
return NotificationWrapper(self.handle,
event_notification_alloc(self.handle,
tuple.this))
def notify(self, en):
"""
Send a notification.
"""
return event_notify(self.handle, en.notification)
def run(self):
"""
Main loop used to wait for and process events.
"""
while True:
rc = c_event_poll_blocking(self.handle, 0)
if rc != 0:
sys.stderr.write("c_event_poll_blocking: " + str(rc) + "\n")
pass
else:
for ev in self._callbacks():
self.handle_event(ev)
pass
time.sleep(0.1)
pass
pass
return
pass
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment