Example #1
0
class SettingStorage(object):
    #
    def __init__(self, *args, topic='storage', connector=None, **kwargs):
        if isinstance(connector, RedisClient):
            self.__use_shared_connector = True
            self.__connector = connector
        else:
            self.__use_shared_connector = False
            self.__connector = RedisClient(**kwargs)
        #
        self.__topic = topic
        self.__default_key = ':'.join([self.__connector.CHANNEL_GROUP, self.__topic])
        #
        super(SettingStorage, self).__init__()
    #
    ##
    @property
    def connector(self):
        return self.__connector
    #
    ##
    def get(self, key:str):
        value = self.__open_connection().get(self.__gen_absolute_key(key))
        if isinstance(value, bytes):
            value = value.decode('utf-8')
        if isinstance(value, str):
            obj, err = json_loads(value)
            if err:
                raise err
            return obj
        return value
    #
    ##
    def store(self, key:str, obj:Union[dict,list,str,float,int,bool]):
        value, err = json_dumps(obj)
        if err:
            raise err
        return self.__open_connection().set(self.__gen_absolute_key(key), value)
    #
    ##
    def clear(self, key:str):
        return self.__open_connection().delete(self.__gen_absolute_key(key))
    #
    ##
    def close(self):
        if not self.__use_shared_connector:
            self.__connector.close()
        if LOG.isEnabledFor(logging.DEBUG):
            LOG.log(logging.DEBUG, "SettingStorage has closed")
    #
    #
    def __open_connection(self):
        return assure_not_null(self.__connector.rewind().connect(pinging=False, retrying=False))
    #
    def __gen_absolute_key(self, key):
        if key:
            return self.__default_key + ':' + str(key)
        return self.__default_key
Example #2
0
 def __init__(self, *args, connector=None, **kwargs):
     if isinstance(connector, RedisClient):
         self.__use_shared_connector = True
         self.__connector = connector
     else:
         self.__use_shared_connector = False
         self.__connector = RedisClient(**kwargs)
     #
     self.CHANNEL_PREFIX = self.__connector.CHANNEL_GROUP + ':'
     #
     super(SettingPublisher, self).__init__()
Example #3
0
 def __init__(self, topic='counter', connector=None, **kwargs):
     if isinstance(connector, RedisClient):
         self.__use_shared_connector = True
         self.__connector = connector
     else:
         self.__use_shared_connector = False
         self.__connector = RedisClient(**kwargs)
     #
     self.__topic = topic
     self.__default_key = ':'.join([self.__connector.CHANNEL_GROUP, self.__topic])
     #
     super(AutoIncrement, self).__init__()
Example #4
0
 def __init__(self, *args, topic='storage', connector=None, **kwargs):
     if isinstance(connector, RedisClient):
         self.__use_shared_connector = True
         self.__connector = connector
     else:
         self.__use_shared_connector = False
         self.__connector = RedisClient(**kwargs)
     #
     self.__topic = topic
     self.__default_key = ':'.join([self.__connector.CHANNEL_GROUP, self.__topic])
     #
     super(SettingStorage, self).__init__()
Example #5
0
 def __init__(self, *args, connector=None, **kwargs):
     if isinstance(connector, RedisClient):
         self.__use_shared_connector = True
         self.__connector = connector
     else:
         self.__use_shared_connector = False
         self.__connector = RedisClient(**kwargs)
     #
     self.__transformer = transform_json_data
     #
     self.CHANNEL_PATTERN = self.__connector.CHANNEL_GROUP + '*'
     #
     super(SettingSubscriber, self).__init__()
Example #6
0
class AutoIncrement(object):
    #
    def __init__(self, topic='counter', connector=None, **kwargs):
        if isinstance(connector, RedisClient):
            self.__use_shared_connector = True
            self.__connector = connector
        else:
            self.__use_shared_connector = False
            self.__connector = RedisClient(**kwargs)
        #
        self.__topic = topic
        self.__default_key = ':'.join([self.__connector.CHANNEL_GROUP, self.__topic])
        #
        super(AutoIncrement, self).__init__()
    #
    ##
    @property
    def connector(self):
        return self.__connector
    #
    ##
    def init(self, label:Optional[str]=None, value:Optional[int]=0):
        return self.__open_connection().set(self.__gen_absolute_key(label), value, nx=True)
    #
    ##
    def incr(self, label:Optional[str]=None, amount:Optional[int]=1):
        return self.__open_connection().incr(self.__gen_absolute_key(label), amount=amount)
    #
    #
    def clear(self, label:Optional[str]=None):
        return self.__open_connection().delete(self.__gen_absolute_key(label))
    #
    #
    def reset(self, label:Optional[str]=None, value:Optional[int]=0):
        return self.__open_connection().set(self.__gen_absolute_key(label), value)
    #
    #
    def close(self):
        if not self.__use_shared_connector:
            self.__connector.close()
        if LOG.isEnabledFor(logging.DEBUG):
            LOG.log(logging.DEBUG, "AutoIncrement has closed")
    #
    #
    def __open_connection(self):
        return assure_not_null(self.__connector.rewind().connect(pinging=False, retrying=False))
    #
    def __gen_absolute_key(self, label):
        if label:
            return self.__default_key + ':' + str(label)
        return self.__default_key
Example #7
0
class SettingSubscriber(object):
    #
    def __init__(self, *args, connector=None, **kwargs):
        if isinstance(connector, RedisClient):
            self.__use_shared_connector = True
            self.__connector = connector
        else:
            self.__use_shared_connector = False
            self.__connector = RedisClient(**kwargs)
        #
        self.__transformer = transform_json_data
        #
        self.CHANNEL_PATTERN = self.__connector.CHANNEL_GROUP + '*'
        #
        super(SettingSubscriber, self).__init__()
    #
    ##
    @property
    def connector(self):
        return self.__connector
    #
    ##
    @property
    def pubsub(self):
        ps = assure_not_null(self.__connector.connect()).pubsub()
        ps.psubscribe(**{self.CHANNEL_PATTERN: self.__process_event})
        return ps
    #
    ##
    __pubsub_thread = None
    __pubsub_lock = threading.RLock()
    #
    def start(self):
        with self.__pubsub_lock:
            if self.__pubsub_thread is None:
                self.__pubsub_thread = self.__run_in_thread(sleep_time=0.001)
                if LOG.isEnabledFor(logging.DEBUG):
                    LOG.log(logging.DEBUG, "SettingSubscriber has started")
            return self.__pubsub_thread
    #
    def stop(self):
        return self.close()
    #
    def close(self):
        with self.__pubsub_lock:
            if self.__pubsub_thread is not None:
                self.__pubsub_thread.stop()
            #
            if not self.__use_shared_connector:
                self.__connector.close()
            #
            if self.__pubsub_thread is not None:
                self.__pubsub_thread.join()
                self.__pubsub_thread = None
            #
            if LOG.isEnabledFor(logging.DEBUG):
                LOG.log(logging.DEBUG, "SettingSubscriber has stopped")
    #
    #
    def __run_in_thread(self, auto_start=True, sleep_time=0, daemon=False):
        thread = PubSubWorkerThread(self, sleep_time, daemon=daemon)
        if auto_start:
            thread.start()
        return thread
    #
    ##
    __transformer: Optional[Callable[[Dict], Tuple[Dict, Any]]] = None
    #
    def set_transformer(self, transformer: Callable[[Dict], Tuple[Dict, Any]]):
        if callable(transformer):
            self.__transformer = transformer
        return self
    #
    ##
    __event_mappings: Optional[Dict[Callable[[Dict, Any], bool], Tuple[Callable[[Dict, Any], None],...]]] = None
    #
    def add_event_handler(self, match: Callable[[Dict, Any], bool], *reset: Callable[[Dict, Any], None]):
        if self.__event_mappings is None:
            self.__event_mappings = dict()
        if not callable(match):
            raise ValueError('[match] must be callable')
        if not reset:
            raise ValueError('[reset] list must not be empty')
        for i, func in enumerate(reset):
            if not callable(func):
                raise ValueError('function#{0} must be callable'.format(i))
        self.__event_mappings[match] = reset
        return self
    #
    def __process_event(self, message):
        if self.__event_mappings is None:
            if LOG.isEnabledFor(logging.DEBUG):
                LOG.log(logging.DEBUG, "handler_mappings is empty (no service has been registered yet)")
            return
        #
        if self.__transformer is not None:
            msg, err = self.__transformer(message)
        else:
            msg, err = (message, None)
        #
        for match, reaction in self.__event_mappings.items():
            if match(msg, err):
                if LOG.isEnabledFor(logging.DEBUG):
                    LOG.log(logging.DEBUG, "the matching function [{0}] is matched".format(match.__name__))
                for reset in reaction:
                    if callable(reset):
                        if LOG.isEnabledFor(logging.DEBUG):
                            LOG.log(logging.DEBUG, "the handler [{0}] is triggered".format(reset.__name__))
                        reset(msg, err)
    #
    #
    def register_receiver(self, capsule: SettingCapsule):
        def wrap_capsule_reset(message, err):
            return capsule.reset(parameters=extract_parameters(message, err))
        if isinstance(capsule, SettingCapsule):
            self.add_event_handler(match_by_label(capsule.label), wrap_capsule_reset)
        return capsule
Example #8
0
class SettingPublisher(object):
    #
    def __init__(self, *args, connector=None, **kwargs):
        if isinstance(connector, RedisClient):
            self.__use_shared_connector = True
            self.__connector = connector
        else:
            self.__use_shared_connector = False
            self.__connector = RedisClient(**kwargs)
        #
        self.CHANNEL_PREFIX = self.__connector.CHANNEL_GROUP + ':'
        #
        super(SettingPublisher, self).__init__()

    #
    ##
    @property
    def connector(self):
        return self.__connector

    #
    ##
    def publish(self,
                message: Union[Dict, bytes, str, int, float],
                label: Optional[Union[bytes, str]] = None,
                with_datetime: Optional[bool] = False,
                raise_on_error: Optional[bool] = False) -> Optional[Exception]:
        try:
            self.__publish_or_error(message,
                                    label=label,
                                    with_datetime=with_datetime)
            return None
        except Exception as err:
            if raise_on_error:
                raise err
            return err

    #
    #
    def __publish_or_error(self, message, label=None, with_datetime=False):
        if label is None:
            channel_name = self.__connector.CHANNEL_GROUP
        else:
            if isinstance(label, bytes):
                label = label.decode('utf-8')
            else:
                label = str(label)
            channel_name = self.CHANNEL_PREFIX + label
        #
        if isinstance(message, (dict, list)):
            message, err = json_dumps(message, with_datetime=with_datetime)
            if err:
                if LOG.isEnabledFor(logging.ERROR):
                    LOG.log(logging.ERROR, err)
                raise err
        elif not self.__is_valid_type(message):
            errmsg = "Invalid type of input: '%s'. Only a dict, list, bytes, string, int or float accepted." % type(
                message)
            if LOG.isEnabledFor(logging.ERROR):
                LOG.log(logging.ERROR, errmsg)
            raise ValueError(errmsg)
        #
        if LOG.isEnabledFor(logging.DEBUG):
            LOG.log(logging.DEBUG, "publish() a message [%s] to channel [%s]",
                    str(message), channel_name)
        #
        self.__open_connection().publish(channel_name, message)

    #
    #
    def close(self):
        if not self.__use_shared_connector:
            self.__connector.close()
        if LOG.isEnabledFor(logging.DEBUG):
            LOG.log(logging.DEBUG, "SettingPublisher has closed")

    #
    #
    def __open_connection(self):
        return assure_not_null(self.__connector.rewind().connect(
            pinging=False, retrying=False))

    #
    #
    @staticmethod
    def __is_valid_type(data):
        return isinstance(data,
                          (bytes, str, float)) or (isinstance(data, int) and
                                                   (type(data) != type(True)))
#!/usr/bin/env python3

import __init__

from datetime import datetime

from configator.engine.connector import RedisClient
from configator.engine import SettingSubscriber
from configator.utils.function_util import match_by_label, transform_json_data
from configator.utils.signal_util import hook_signal

#------------------------------------------------------------------------------

c = RedisClient()

#------------------------------------------------------------------------------


def trigger1(message, *args, **kwargs):
    print('1. clear the config')


def trigger2(message, *args, **kwargs):
    print('2. update the config: %s' % str(message))


def trigger3(message, *args, **kwargs):
    print('3. reset the engine')
    print()