import json import random import threading from platypush.config import Config from platypush.message import Message from platypush.utils import get_event_class_by_type class Event(Message): """ Event message class """ def __init__(self, target=None, origin=None, id=None, **kwargs): """ Params: target -- Target node [String] origin -- Origin node (default: current node) [String] id -- Event ID (default: auto-generated) kwargs -- Additional arguments for the event [kwDict] """ self.id = id if id else self._generate_id() self.target = target if target else Config.get('device_id') self.origin = origin if origin else Config.get('device_id') self.type = '{}.{}'.format(self.__class__.__module__, self.__class__.__name__) self.args = kwargs @classmethod def build(cls, msg): """ Builds an event message from a JSON UTF-8 string/bytearray, a dictionary, or another Event """ msg = super().parse(msg) event_type = msg['args'].pop('type') event_class = get_event_class_by_type(event_type) args = { 'target' : msg['target'], 'origin' : msg['origin'], **(msg['args'] if 'args' in msg else {}), } args['id'] = msg['id'] if 'id' in msg else cls._generate_id() return event_class(**args) def matches_condition(self, condition): """ If the event matches an event condition, it will return True and a dictionary containing any parsed arguments, otherwise False and {} Params: -- condition -- The platypush.event.hook.EventCondition object """ parsed_args = {} if not isinstance(self, condition.type): return [False, parsed_args] for (attr, value) in condition.args.items(): # TODO Be more sophisticated, not only simple match options! if not hasattr(self.args, attr): return [False, parsed_args] if isinstance(self.args[attr], str) and not value in self.args[attr]: return [False, parsed_args] elif self.args[attr] != value: return [False, parsed_args] return [True, parsed_args] @staticmethod def _generate_id(): """ Generate a unique event ID """ id = '' for i in range(0,16): id += '%.2x' % random.randint(0, 255) return id def __str__(self): """ Overrides the str() operator and converts the message into a UTF-8 JSON string """ return json.dumps({ 'type' : 'event', 'target' : self.target, 'origin' : self.origin if hasattr(self, 'origin') else None, 'id' : self.id if hasattr(self, 'id') else None, 'args' : { 'type' : self.type, **self.args, }, }) # XXX Should be a stop Request, not an Event class StopEvent(Event): """ StopEvent message. When received on a Bus, it will terminate the listening thread having the specified ID. Useful to keep listeners in sync and make them quit when the application terminates """ def __init__(self, target, origin, thread_id, id=None, **kwargs): """ Constructor. Params: target -- Target node origin -- Origin node thread_id -- thread_iden() to be terminated if listening on the bus id -- Event ID (default: auto-generated) kwargs -- Extra key-value arguments """ super().__init__(target=target, origin=origin, id=id, thread_id=thread_id, **kwargs) def targets_me(self): """ Returns true if the stop event is for the current thread """ return self.args['thread_id'] == threading.get_ident() # vim:sw=4:ts=4:et: