def deliver(self, event): """ Local delivery of an event. Returns a Deferred object with the final status of the deliver operation. """ Trace("%s deliver (%s,%s,%s)"% (self.getUri(), event.getType(), event.getSource(), event.getPayload()), context="EventLib.EventPubSub") (evtyp, evsrc) = getEventTypeSource(event) if isSubscribeEvent(evtyp): for (e,t,handler) in self._sub.iterateWild(evtyp, evsrc): # Deliver to watchers only (no wildcard event type) if e == URI.EventSubscribeType: Trace("%s - to watcher %s"%(self.getUri(), handler.getUri()), context="EventLib.EventPubSub") sts = handler.handleEvent(event) if sts.syncValue() != StatusVal.OK: return sts else: for handler in self._sub.iterate(evtyp, evsrc): Trace("%s - to handler %s (%s,%s)"%(self.getUri(), handler.getUri(), event.getType(), event.getSource()), context="EventLib.EventPubSub") sts = handler.handleEvent(event) if sts.syncValue() != StatusVal.OK: return sts return makeDeferred(StatusVal.OK)
def subscribe(self, interval, handler, evtype=None, source=None): """ Subscribe an event handler to an event/source combination. 'interval' is a time interval, in seconds, for which the subscription is to be maintained - if zero, no subscription is created, and any existing subscription is cancelled. Returns a Deferred status value is returned indicating the outcome of the operation. """ Trace("%s subscribe %us, handler %s to (%s,%s)"% (self.getUri(), interval, str(handler), evtype, source), context="EventLib.EventPubSub") sts = self.unsubscribe(handler, evtype, source) if interval != 0: self._sub.insert(evtype, source, handler) self._subcount += 1 handler.initSubscription(StatusVal.SUBSCRIBED) # Publish subscribe request and notify events sts = self.publishSubscription(handler, interval, evtype, source) if sts.syncValue() != StatusVal.OK: Trace("publish subscription returns %s"%(str(sts.syncValue())), context="EventLib.EventPubSub") self.unsubscribe(handler, evtype, source) else: sts = makeDeferred(StatusVal.SUBSCRIBED) return sts
def receive(self, fromrouter, envelope): """ Receive an event from an external event router. The event received is wrapped in a forwarding envelope, which contains additional information about the event delivery path that is used, possibly among other things, to detect event forwarding loops. Returns a Deferred object with the final status of the receive operation. """ sts = makeDeferred(StatusVal.OK) event = envelope.unWrap(self.getUri()) # unWrap handles loop-detection if event: Trace("%s receive %s from %s"%(self.getUri(),str(event), fromrouter), "EventLib.EventRouter") self.deliver(event) sub = openSubscribeEvent(isSubscribeEvent, event) Trace("%s openSubscribeEvent %s"%(self.getUri(),sub), "EventLib.EventRouter") if sub: # New subscription request self.doSubscribeRequest(fromrouter, sub[2], sub[3], sub[4]) newenv = envelope.nextHop(self.getUri()) sts = self.forward(event, newenv) if sub and sub[2] != 0 and sts.syncValue() != StatusVal.OK: # Undo subscription self.doSubscribeRequest(fromrouter, 0, sub[3], sub[4]) return sts
def forward(self, event, envelope): """ Forward an event to any external event routers that have subscribers for this event. This version is a dummy function that must be overridden for event distribution nodes that may route events to other nodes. Returns a Deferred object with the final status of the forward operation. """ return makeDeferred(StatusVal.OK)
def queueItem(self, item): """ Add item to the queue, and return a deferred object that fires when an item is removed (or the queue is empty). """ Trace("%s queueItem (%s)"%(self.getUri(),item), "EventLib.EventRelayHTTPC") if not self._closing: self._queue.put(item) return makeQueueDeferred(StatusVal.OK, self._queue, self._event) return makeDeferred(StatusVal.OK)
def publish(self, agent, event): """ Publish an event. The event source is taken from the event itself; the 'agent' parameter provides an EventAgent context that may be used for diagnostic or security purposes. """ if not self._closing: self._queue.put( (agent, event) ) # Let the router thread handle the event return makeQueueDeferred(StatusVal.OK, self._queue, self._event) return makeDeferred(StatusVal.SHUTDOWN)
def initSubscription(self, status): """ Subscription notification. If defined, the notification function is called with this event handler object and the subscription status value as arguments. """ if self._initSubscription: sts = self._initSubscription(self, status) else: sts = makeDeferred(status) ### Trace("initSubscription(%s,%s) -> %s"%(str(self),str(status),str(sts)), "EventLib.EventHandler") return sts
def queueItem(self, item): """ Add item to the queue, and return a deferred object that fires when an item is removed (or the queue is empty). """ Trace("%s queueItem (%s)" % (self.getUri(), item), "EventLib.EventRelayHTTPC") if not self._closing: self._queue.put(item) return makeQueueDeferred(StatusVal.OK, self._queue, self._event) return makeDeferred(StatusVal.OK)
def queueItem(self, item): """ Add an item to the queue, and returned a Deferred object that fires when an item is removed or the queue is empty. """ Trace("%s queueItem: %s"%(self.getUri(),str(item)), "EventLib.EventRelayHTTPS") if not self._closing: self._queue.put(item) # Waiting for item to be removed from queue means we wait for # the client to make a request, which is not predictable. ### return makeQueueDeferred(StatusVal.OK, self._queue, self._event) return makeDeferred(StatusVal.OK)
def queueItem(self, item): """ Add an item to the queue, and returned a Deferred object that fires when an item is removed or the queue is empty. """ Trace("%s queueItem: %s" % (self.getUri(), str(item)), "EventLib.EventRelayHTTPS") if not self._closing: self._queue.put(item) # Waiting for item to be removed from queue means we wait for # the client to make a request, which is not predictable. ### return makeQueueDeferred(StatusVal.OK, self._queue, self._event) return makeDeferred(StatusVal.OK)
def receive(self, fromrouter, envelope): """ This function receives messages from the associated router and queues them for transmission on the HTTP interface. NOTE: receive and forward here perform loop-check for outgoing events, and add the extra envelope hop for incoming. The sole purpose of this loop-check is to prevent incoming HTTP events from being sent out again. """ event = envelope.unWrap(self.getUri()) if event: Trace("%s receive %s from %s"%(self.getUri(),event,fromrouter), "EventLib.EventRelayHTTPC") return self.queueItem(["forward",envelope]) return makeDeferred(StatusVal.OK)
def unsubscribe(self, handler, evtype=None, source=None): """ Unsubscribe an event handler from an event/source combination. A Deferred status value is returned indicating the outcome of the unsubscribe operation. """ Trace("%s unsubscribe (%s,%s) from %s"%(self.getUri(), evtype, source, str(handler)), context="EventLib.EventPubSub") removed = self._sub.remove(evtype, source, handler) Trace("removed: %s"%(map(str,removed)), context="EventLib.EventPubSub") sts = makeDeferred(StatusVal.UNSUBSCRIBED) if removed: self._subcount -= len(removed) Trace("self._subcount: %u"%(self._subcount), context="EventLib.EventPubSub") handler.endSubscription(StatusVal.UNSUBSCRIBED) # Publish unsubscribe event sts = self.publishSubscription(handler, 0, evtype, source) if sts.syncValue() != StatusVal.OK: Trace("publish unsubscription returns %s"%(str(sts.syncValue())), context="EventLib.EventPubSub") else: sts = makeDeferred(StatusVal.UNSUBSCRIBED) return sts
def publishSubscription(self, handler, interval, evtype, source): """ Local helper to propagate a subscribe or unsubscribe request (unsubscribe is distinguished by interval=0). Don't publish subscriptions to subscribe events (watch requests) as the encoding hack used means these appear as encoded subscription of the kind we're trying to watch. And in any case, there's no point in publishing events for watch requests. """ sts = makeDeferred(StatusVal.OK) if not isSubscribeEvent(evtype): subreq = makeSubscribeEvent(URI.EventSubscribeType, handler.getUri(), interval, evtype, source) sts = self.publish(self.getUri(), subreq) return sts
def handleEvent(self, event): """ Handle an incoming event. If defined, the handler function is called with this event handler object and the event itself as arguments. Exceptions are logged then ignored. """ sts = makeDeferred(StatusVal.OK) if self._handleEvent: try: sts = self._handleEvent(self, event) except Exception, ex: # if any handler throws an exception, log and continue. Info("Exception %s" % (ex), "EventLib.EventHandler")
def handleEvent(self, event): """ Handle an incoming event. If defined, the handler function is called with this event handler object and the event itself as arguments. Exceptions are logged then ignored. """ sts = makeDeferred(StatusVal.OK) if self._handleEvent: try: sts = self._handleEvent(self, event) except Exception, ex: # if any handler throws an exception, log and continue. Info("Exception %s"%(ex), "EventLib.EventHandler")
def receive(self, fromrouter, envelope): """ This function receives messages from the associated router and queues them for transmission on the HTTP interface. NOTE: receive and forward here perform loop-check for outgoing events, and add the extra envelope hop for incoming. The sole purpose of this loop-check is to prevent incoming HTTP events from being sent out again. """ event = envelope.unWrap(self.getUri()) if event: Trace("%s receive %s from %s" % (self.getUri(), event, fromrouter), "EventLib.EventRelayHTTPC") return self.queueItem(["forward", envelope]) return makeDeferred(StatusVal.OK)
def forward(self, event, envelope): """ Forward an event to any external event routers that have subscribers for this event. The event to be delivered is supplied bare and also wrapped in a forwarding envelope, which contains additional information about the event delivery path that is used, possibly among other things, to detect event forwarding loops. Returns a Deferred object with the final status of the forward operation. """ Trace("%s forward %s"%(self.getUri(),str(event)), "EventLib.EventRouter") sub = openSubscribeEvent(isSubscribeEvent, event) if sub: # Subscribe events routed per static routing table and subscribed event type/source for router in self._fwdroute.iterate(sub[3], sub[4]): sts = router.receive(self, envelope) if sts.syncValue() != StatusVal.OK: return sts else: # Other events routed per dynamic routing table and event type/source for router in self._fwdtable.iterate(event.getType(), event.getSource()): sts = router.receive(self, envelope) if sts.syncValue() != StatusVal.OK: return sts return makeDeferred(StatusVal.OK)