tbevent.py.tail 8.74 KB
Newer Older
1
2
3
4
5
6
7
8
9
# -*- 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
#

10
import sys
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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)

Timothy Stack's avatar
 
Timothy Stack committed
68
69
70
    def getTimeline(self, args):
        return event_notification_get_timeline(self.handle, self.notification)

71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
    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


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
class EventError:
    """
    Base class for event related exceptions.
    """
    def __init__(self, code):
        self.args = code,
        return
    
    pass


class EventTimedOutError(EventError):
    """
    Exception raised when the run() method of EventClient timed out.
    """
    def __init__(self, timeout):
        self.args = timeout,
        return
    
    pass


# Ugh, elvin likes to crash if we unregister all of the handles, so we keep
# a dummy one around just to keep things happy.
_hack_handle = None

155
156
157
158
class EventClient:
    """
    Event client class, mostly just wraps the SWIG'd versions of the functions.
    """
159
    
Timothy Stack's avatar
 
Timothy Stack committed
160
    def __init__(self, server=None, port=None, url=None, keyfile=None):
161
162
163
164
165
166
167
        """
        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.
        """
168
169
        global _hack_handle
        
170
171
172
173
174
175
176
177
178
179
        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
180
                pass
181
            pass
Timothy Stack's avatar
 
Timothy Stack committed
182
183
184
185
186
187
188
189

        if keyfile:
            self.handle = event_register_withkeyfile(url, 0, keyfile)
            pass
        else:
            self.handle = event_register(url, 0)
            pass
        
190
191
192
193
194
195
196
197
198
        self.timeout = 0
        
        if not _hack_handle:
            # Open a handle for the sole purpose of keeping the event library
            # from calling the elvin cleanup function, because elvin likes to
            # segfault when it has been init'd/clean'd multiple times.
            _hack_handle = event_register(url, 0)
            pass
        
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
        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.
220
221

        @return None to continue processing events, any other value to stop.
222
        """
223
        return None
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246

    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)

247
248
249
250
251
252
253
    def set_timeout(self, timeout):
        """
        @param timeout The timeout, in seconds, for the run() loop.
        """
        self.timeout = timeout * 1000
        return

254
255
256
    def run(self):
        """
        Main loop used to wait for and process events.
257
258

        @return The not None value returned by handle_event.
259
        """
260
261
262
        retval = None
        while not retval:
            rc = c_event_poll_blocking(self.handle, self.timeout)
263
264
            if rc != 0:
                sys.stderr.write("c_event_poll_blocking: " + str(rc) + "\n")
265
                raise EventError, rc
266
267
            else:
                for ev in self._callbacks():
268
269
270
271
272
273
274
275
276
277
278
279
280
281
                    retval = self.handle_event(ev)
                    if retval:
                        # Not None return value, stop the bus.
                        break
                    pass
                else:
                    if self.timeout != 0:
                        # We're making a bit of an assumption here that no
                        # callbacks means a timeout occurred, oh well.
                        raise EventTimedOutError, self.timeout
                    pass
                
                if not retval:
                    time.sleep(0.1) # Forcefully slow down the poll.
282
283
284
                    pass
                pass
            pass
285
        return retval
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
    def poll(self):
        """
        Polling interface; returns events to caller, one at a time.
        """

        while True:
            try:
                #
                # First see if anything not yet delivered.
                #
                ev = CallbackIterator(self.handle).next()
                return ev;
            except StopIteration, e:
                pass
            
            rc = c_event_poll_blocking(self.handle, 0)        
            if rc != 0:
                sys.stderr.write("c_event_poll_blocking: " + str(rc) + "\n")
                raise IOError, "Reading events"
            pass
307
308
    pass