Source code for divera.triggers.socketevents

import abc
import logging
import traceback
import typing

import divera.utils
from divera.models.alarms import Alarm
from divera.models.events import Event
from divera.models.message import Message
from divera.models.message_channel import MessageChannel
from divera.models.news import News

from . import Trigger


[docs]class SocketEvent(Trigger): def __init__( self, data, ): self.data = data
[docs] @staticmethod @abc.abstractmethod def matches(data) -> bool: return False
[docs]class UnspecifiedSocketEvent(SocketEvent):
[docs] @staticmethod def matches(data) -> bool: return True
[docs]class ClusterMonitorEvent(SocketEvent):
[docs] @staticmethod def matches(data) -> bool: return data['type'] == 'cluster-monitor'
[docs]class ClusterPullTrigger(SocketEvent): models = None action_path = [ 'pull', 'action', ] @property def action(self): d = self.data try: for step in self.action_path: d = d[step] except KeyError: return None return d
[docs] @staticmethod def matches(data) -> bool: return data['type'] == 'cluster-pull'
[docs]class ClusterPullAlarm(ClusterPullTrigger): models = ( Alarm, )
[docs] @staticmethod def matches(data) -> bool: return ClusterPullTrigger.matches(data=data) and data['pull']['type'] == 'alarm'
[docs]class ClusterPullEvent(ClusterPullTrigger): models = ( Event, )
[docs] @staticmethod def matches(data) -> bool: return ClusterPullTrigger.matches(data=data) and data['pull']['type'] == 'event'
[docs]class ClusterTrigger(ClusterPullTrigger, abc.ABC): @property @abc.abstractmethod def data_path(self) -> list: return [ ] @property def object(self): if type(self.models) in [list, tuple]: model = self.models[0] else: model = self.models data = self.data for p in self.data_path: data = data[p] return model( data=data, )
[docs]class ClusterMessage(ClusterTrigger): models = ( Message, ) data_path = [ 'message', ]
[docs] @staticmethod def matches(data) -> bool: """ Matches :code:`user-message` and :code:`cluster-message`. * :code:`user-message` is triggered when a message is received in a message channel that is related to something * :code:`cluster-message` is triggered when a message is received in the default message channel """ return data['type'] in ['user-message', 'cluster-message'] and 'message' in data.keys()
@property def message(self) -> Message: if 'message' in self.data: return Message( data=self.data['message'], ) @property def message_channel(self) -> MessageChannel: if 'message_channel' in self.data: return MessageChannel( data=self.data['message_channel'], )
[docs]class MessageDeletedEvent(ClusterMessage):
[docs] @staticmethod def matches(data) -> bool: return ClusterMessage.matches(data) and data['message']['deleted']
[docs]class ClusterPullNews(ClusterPullTrigger): models = ( News, )
[docs] @staticmethod def matches(data) -> bool: return ClusterPullTrigger.matches(data=data) and data['pull']['type'] == 'news'
[docs]class ClusterPullMessageChannel(ClusterPullTrigger): models = ( MessageChannel, )
[docs] @staticmethod def matches(data) -> bool: return ClusterPullTrigger.matches(data=data) and data['pull']['type'] == 'message-channel'
[docs]class UnspecifiedClusterPull(ClusterPullTrigger): models = None
[docs]class UserStatusChange(SocketEvent):
[docs] @staticmethod def matches(data) -> bool: return data['type'] == 'user-status'
[docs]def get_matching_subclasses( data, cls: SocketEvent = SocketEvent, sort: bool = True, ) -> typing.List[typing.Type[SocketEvent]]: subclasses = [] for s_cls in cls.__subclasses__(): for r in get_matching_subclasses( data=data, cls=s_cls, sort=False, ): subclasses.append(r) try: if abc.ABC not in cls.__bases__: if cls.matches(data): subclasses.append(cls) except Exception as e: logging.error( f'{cls.__name__} is no match for data of type {type(data).__name__}', ) logging.error(''.join(traceback.format_exception(e))) if sort: return sorted( # Sort most specific (= most deeply nested) classes first sorted( # Sort unspecified classes last subclasses, key=lambda cls_: cls_.__name__.startswith('Unspecified'), ), key=lambda x: divera.utils.get_nesting_depth(x, parent_cls=SocketEvent), reverse=True, ) else: return subclasses