Added code for handling procedures - solves #1

This commit is contained in:
Fabio Manganiello 2017-12-25 17:23:09 +01:00
parent 6e019865bc
commit 617c0f8a07
5 changed files with 79 additions and 16 deletions

View File

@ -9,10 +9,10 @@ from .bus import Bus
from .config import Config from .config import Config
from .context import register_backends from .context import register_backends
from .event.processor import EventProcessor 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.event import Event, StopEvent
from .message.request import Request from .message.request import Request
from .message.response import Response from .message.response import Response
from .procedure import Procedure
__author__ = 'Fabio Manganiello <blacklight86@gmail.com>' __author__ = 'Fabio Manganiello <blacklight86@gmail.com>'
__version__ = '0.6' __version__ = '0.6'
@ -75,9 +75,15 @@ class Daemon(object):
msg -- platypush.message.Message instance """ msg -- platypush.message.Message instance """
if isinstance(msg, Request): if isinstance(msg, Request):
logging.info('Processing request: {}'.format(msg)) if msg.action.startswith('procedure.'):
msg.execute(n_tries=self.n_tries) 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 self.processed_requests += 1
if self.requests_to_process \ if self.requests_to_process \
and self.processed_requests >= self.requests_to_process: and self.processed_requests >= self.requests_to_process:

View File

@ -62,14 +62,14 @@ class Config(object):
if 'device_id' not in self._config: if 'device_id' not in self._config:
self._config['device_id'] = socket.gethostname() self._config['device_id'] = socket.gethostname()
self.backends = {}
self.plugins = {}
self.event_hooks = {}
self.procedures = {}
self._init_components() self._init_components()
def _init_components(self): def _init_components(self):
self.backends = {}
self.plugins = {}
self.event_hooks = {}
for key in self._config.keys(): for key in self._config.keys():
if key.startswith('backend.'): if key.startswith('backend.'):
backend_name = '.'.join(key.split('.')[1:]) backend_name = '.'.join(key.split('.')[1:])
@ -77,6 +77,9 @@ class Config(object):
elif key.startswith('event.hook.'): elif key.startswith('event.hook.'):
hook_name = '.'.join(key.split('.')[2:]) hook_name = '.'.join(key.split('.')[2:])
self.event_hooks[hook_name] = self._config[key] 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: else:
self.plugins[key] = self._config[key] self.plugins[key] = self._config[key]
@ -98,6 +101,12 @@ class Config(object):
if _default_config_instance is None: _default_config_instance = Config() if _default_config_instance is None: _default_config_instance = Config()
return _default_config_instance.event_hooks 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 @staticmethod
def get_default_pusher_backend(): def get_default_pusher_backend():
""" """

View File

@ -5,22 +5,21 @@ import traceback
from threading import Thread from threading import Thread
from threading import Thread
from platypush.message import Message from platypush.message import Message
from platypush.message.response import Response 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): class Request(Message):
""" Request message class """ """ 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: Params:
target -- Target node [String] target -- Target node [String]
action -- Action to be executed (e.g. music.mpd.play) [String] action -- Action to be executed (e.g. music.mpd.play) [String]
origin -- Origin node [String] origin -- Origin node [String]
id -- Message ID, or None to get it auto-generated 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] args -- Additional arguments for the action [Dict]
""" """
@ -29,7 +28,7 @@ class Request(Message):
self.action = action self.action = action
self.origin = origin self.origin = origin
self.args = args self.args = args
self.backend = None self.backend = backend
@classmethod @classmethod
def build(cls, msg): def build(cls, msg):
@ -58,7 +57,7 @@ class Request(Message):
n_tries -- Number of tries in case of failure before raising a RuntimeError n_tries -- Number of tries in case of failure before raising a RuntimeError
""" """
def _thread_func(n_tries): 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) plugin = get_or_load_plugin(module_name)

View File

@ -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:

View File

@ -35,14 +35,13 @@ def get_or_load_plugin(plugin_name, reload=False):
plugin = plugin_class(**plugin_conf) plugin = plugin_class(**plugin_conf)
modules[plugin_name] = plugin modules[plugin_name] = plugin
except AttributeError as e: except AttributeError as e:
logging.warning('No such class in {}: {}'.format( logging.warning('No such class in {}: {}'.format(plugin_name, cls_name))
plugin_name, cls_name))
raise RuntimeError(e) raise RuntimeError(e)
return plugin return plugin
def get_module_and_name_from_action(action): def get_module_and_method_from_action(action):
""" Input : action=music.mpd.play """ Input : action=music.mpd.play
Output : ('music.mpd', 'play') """ Output : ('music.mpd', 'play') """