diff --git a/platypush/__init__.py b/platypush/__init__.py index 54f4769343..71fa36abb0 100644 --- a/platypush/__init__.py +++ b/platypush/__init__.py @@ -9,10 +9,10 @@ from .bus import Bus from .config import Config from .context import register_backends from .event.processor import EventProcessor -from .utils import get_or_load_plugin, get_module_and_name_from_action from .message.event import Event, StopEvent from .message.request import Request from .message.response import Response +from .procedure import Procedure __author__ = 'Fabio Manganiello ' __version__ = '0.6' @@ -75,9 +75,15 @@ class Daemon(object): msg -- platypush.message.Message instance """ if isinstance(msg, Request): - logging.info('Processing request: {}'.format(msg)) - msg.execute(n_tries=self.n_tries) + if msg.action.startswith('procedure.'): + logging.info('Executing procedure request: {}'.format(msg)) + proc_name = msg.action.split('.')[-1] + proc_config = Config.get_procedures()[proc_name] + msg = Procedure.build(name=proc_name, requests=proc_config, backend=msg.backend, id=msg.id) + else: + logging.info('Processing request: {}'.format(msg)) + msg.execute(n_tries=self.n_tries) self.processed_requests += 1 if self.requests_to_process \ and self.processed_requests >= self.requests_to_process: diff --git a/platypush/config/__init__.py b/platypush/config/__init__.py index 66d3ae6a4d..6828ebee80 100644 --- a/platypush/config/__init__.py +++ b/platypush/config/__init__.py @@ -62,14 +62,14 @@ class Config(object): if 'device_id' not in self._config: self._config['device_id'] = socket.gethostname() + self.backends = {} + self.plugins = {} + self.event_hooks = {} + self.procedures = {} self._init_components() def _init_components(self): - self.backends = {} - self.plugins = {} - self.event_hooks = {} - for key in self._config.keys(): if key.startswith('backend.'): backend_name = '.'.join(key.split('.')[1:]) @@ -77,6 +77,9 @@ class Config(object): elif key.startswith('event.hook.'): hook_name = '.'.join(key.split('.')[2:]) self.event_hooks[hook_name] = self._config[key] + elif key.startswith('procedure.'): + procedure_name = '.'.join(key.split('.')[1:]) + self.procedures[procedure_name] = self._config[key] else: self.plugins[key] = self._config[key] @@ -98,6 +101,12 @@ class Config(object): if _default_config_instance is None: _default_config_instance = Config() return _default_config_instance.event_hooks + @staticmethod + def get_procedures(): + global _default_config_instance + if _default_config_instance is None: _default_config_instance = Config() + return _default_config_instance.procedures + @staticmethod def get_default_pusher_backend(): """ diff --git a/platypush/message/request/__init__.py b/platypush/message/request/__init__.py index cb92b0d002..0526cbcc45 100644 --- a/platypush/message/request/__init__.py +++ b/platypush/message/request/__init__.py @@ -5,22 +5,21 @@ import traceback from threading import Thread -from threading import Thread - from platypush.message import Message from platypush.message.response import Response -from platypush.utils import get_or_load_plugin, get_module_and_name_from_action +from platypush.utils import get_or_load_plugin, get_module_and_method_from_action class Request(Message): """ Request message class """ - def __init__(self, target, action, origin=None, id=None, args={}): + def __init__(self, target, action, origin=None, id=None, backend=None, args={}): """ Params: target -- Target node [String] action -- Action to be executed (e.g. music.mpd.play) [String] origin -- Origin node [String] id -- Message ID, or None to get it auto-generated + backend -- Backend connected to the request, where the response will be delivered args -- Additional arguments for the action [Dict] """ @@ -29,7 +28,7 @@ class Request(Message): self.action = action self.origin = origin self.args = args - self.backend = None + self.backend = backend @classmethod def build(cls, msg): @@ -58,7 +57,7 @@ class Request(Message): n_tries -- Number of tries in case of failure before raising a RuntimeError """ def _thread_func(n_tries): - (module_name, method_name) = get_module_and_name_from_action(self.action) + (module_name, method_name) = get_module_and_method_from_action(self.action) plugin = get_or_load_plugin(module_name) diff --git a/platypush/procedure/__init__.py b/platypush/procedure/__init__.py new file mode 100644 index 0000000000..9e2a6880bb --- /dev/null +++ b/platypush/procedure/__init__.py @@ -0,0 +1,50 @@ +import logging + +from ..config import Config +from ..message.request import Request + +class Procedure(object): + """ Procedure class. A procedure is a pre-configured list of requests """ + + def __init__(self, name, requests, backend=None): + """ + Params: + name -- Procedure name + requests -- List of platylist.message.request.Request objects + """ + + self.name = name + self.requests = requests + self.backend = backend + + for req in requests: + req.backend = self.backend + + @classmethod + def build(cls, name, requests, backend=None, id=None, **kwargs): + reqs = [] + for request_config in requests: + request_config['origin'] = Config.get('device_id') + request_config['id'] = id + if 'target' not in request_config: + request_config['target'] = request_config['origin'] + + request = Request.build(request_config) + reqs.append(request) + + return cls(name=name, requests=reqs, backend=backend, **kwargs) + + def execute(self, n_tries=1): + """ + Execute the requests in the procedure + Params: + n_tries -- Number of tries in case of failure before raising a RuntimeError + """ + + logging.info('Executing request {}'.format(self.name)) + for request in self.requests: + request.execute(n_tries) + + +# vim:sw=4:ts=4:et: + diff --git a/platypush/utils/__init__.py b/platypush/utils/__init__.py index 45683d8da1..5ec5849837 100644 --- a/platypush/utils/__init__.py +++ b/platypush/utils/__init__.py @@ -35,14 +35,13 @@ def get_or_load_plugin(plugin_name, reload=False): plugin = plugin_class(**plugin_conf) modules[plugin_name] = plugin except AttributeError as e: - logging.warning('No such class in {}: {}'.format( - plugin_name, cls_name)) + logging.warning('No such class in {}: {}'.format(plugin_name, cls_name)) raise RuntimeError(e) return plugin -def get_module_and_name_from_action(action): +def get_module_and_method_from_action(action): """ Input : action=music.mpd.play Output : ('music.mpd', 'play') """