From c689b9bbf148784514db6b6adccb59a78594bcac Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Sat, 4 Nov 2017 12:28:15 +0100 Subject: [PATCH] New format for messges, using actions instead of plugin names + custom args for each plugin --- README.md | 13 +++++---- runbullet/__init__.py | 32 ++++++++++++++--------- runbullet/bin/pusher | 25 +++++++++--------- runbullet/plugins/__init__.py | 5 ++-- runbullet/plugins/music/__init__.py | 28 -------------------- runbullet/plugins/shell/__init__.py | 10 ++----- runbullet/plugins/switch/__init__.py | 10 ------- runbullet/plugins/switch/wemo/__init__.py | 18 ++++++------- 8 files changed, 54 insertions(+), 87 deletions(-) diff --git a/README.md b/README.md index b8b34eae..4ba369b7 100644 --- a/README.md +++ b/README.md @@ -30,10 +30,12 @@ Testing Some examples: ```shell -echo '{"cmd":"scp /home/user/photos/*.jpg backup_host:/mnt/hd/photos"}' | pusher --target laptop --plugin shell -echo '{"play":true}' | pusher --target raspberrypi --plugin music.mpd +echo '{"cmd":"scp /home/user/photos/*.jpg backup_host:/mnt/hd/photos"}' | pusher --target laptop --action shell.exec +echo '{}' | pusher --target raspberrypi --action music.mpd.play ``` +The logic to execute is specified by the `--action` option, whose format is `package_name.method_name` (with method_name part of the package main class). + Writing your plugins -------------------- @@ -52,11 +54,13 @@ Writing your own `runbullet` plugin, that would execute your own custom logic wh The `__init__.py` will look like this: ```python +import batman + from .. import LightPlugin class LightBatsignalPlugin(LightPlugin): def _init(self): - self.batsignal = batsignal.Batsignal(self.config['intensity']) + self.batsignal = batman.Batsignal(self.config['intensity']) def on(self): self.batsignal.on() @@ -78,6 +82,5 @@ class LightBatsignalPlugin(LightPlugin): 8. Test your new plugin by sending some bullets to it: ```shell -echo '{"on":true}' | pusher --target your_pc --plugin light.batsignal +echo '{}' | pusher --target your_pc --action light.batsignal.on ``` - diff --git a/runbullet/__init__.py b/runbullet/__init__.py index e21578c4..1e39834b 100644 --- a/runbullet/__init__.py +++ b/runbullet/__init__.py @@ -71,20 +71,27 @@ def _init_plugin(plugin_name, reload=False): def _exec_func(body, retry=True): args = {} - plugin_name = body['plugin'] - if 'args' in body: - args = json.loads(body['args']) \ - if isinstance(body['args'], str) \ - else body['args'] + if 'action' not in body: + logging.warn('No action specified') + return + + target = body.pop('target') + tokens = body.pop('action').split('.') + module_name = str.join('.', tokens[:-1]) + method_name = tokens[-1:][0] + + args = json.loads(body) \ + if isinstance(body, str) \ + else body try: - plugin = _init_plugin(plugin_name) + plugin = _init_plugin(module_name) except RuntimeError as e: # Module/class not found return try: - ret = plugin.run(args) + ret = plugin.run(method=method_name, **args) out = None err = None @@ -102,8 +109,8 @@ def _exec_func(body, retry=True): except Exception as e: logging.exception(e) if retry: - logging.info('Reloading plugin {} and retrying'.format(plugin_name)) - _init_plugin(plugin_name, reload=True) + logging.info('Reloading plugin {} and retrying'.format(module_name)) + _init_plugin(module_name, reload=True) _exec_func(body, retry=False) @@ -135,10 +142,6 @@ def _on_push(ws, data): logging.info('Received push addressed to me: {}'.format(body)) - if 'plugin' not in body: - logging.warn('No plugin specified') - return - thread = Thread(target=_exec_func, args=(body,)) thread.start() @@ -222,3 +225,6 @@ Usage: {} [-v] [-h] [-c ] if __name__ == '__main__': main() + +# vim:sw=4:ts=4:et: + diff --git a/runbullet/bin/pusher b/runbullet/bin/pusher index 9fa8a308..b7fe6aab 100755 --- a/runbullet/bin/pusher +++ b/runbullet/bin/pusher @@ -11,11 +11,11 @@ from runbullet import parse_config_file def print_usage(): - print ('''Usage: {} [-h|--help] <-t|--target > <-p|--plugin > payload + print ('''Usage: {} [-h|--help] <-t|--target > <-a|--action > payload -h, --help:\t\tShow this help and exit -t, --target:\tName of the target device/host - -p, --plugin:\tPlugin to use (e.g. shell or music.mpd) - payload:\t\tArguments to the plugin + -a, --action\tAction to run, it includes both the package name and the method (e.g. shell.exec or music.mpd.play) + payload:\t\tArguments to the action '''.format(sys.argv[0])) def main(): @@ -34,11 +34,11 @@ def main(): 'your PushBullet account'.format(config['pushbullet']['device'])) return - optlist, args = getopt(sys.argv[1:], 'ht:p:', - ['help', 'target=', 'plugin=']) + optlist, args = getopt(sys.argv[1:], 'ht:a:', + ['help', 'target=', 'action=']) target = None - plugin = None + action = None payload = {} for opt, arg in optlist: @@ -47,24 +47,25 @@ def main(): return elif opt == 't' or opt == '--target': target = arg - elif opt == 'p' or opt == '--plugin': - plugin = arg + elif opt == 'a' or opt == '--action': + action = arg if len(args): payload = json.loads(args[0]) else: - payload = sys.stdin.read() + payload = json.loads(sys.stdin.read()) - if not (target and plugin): + if not (target and action): print_usage() return msg = { 'target': target, - 'plugin': plugin, - 'args': payload, + 'action': action, + **payload, } + print('msg: {}'.format(msg)) pb.push_note('', json.dumps(msg), device) diff --git a/runbullet/plugins/__init__.py b/runbullet/plugins/__init__.py index eab40f96..cd9f3212 100644 --- a/runbullet/plugins/__init__.py +++ b/runbullet/plugins/__init__.py @@ -13,8 +13,9 @@ class Plugin(object): pass - def run(self, args): - raise NotImplementedError() + def run(self, method, *args, **kwargs): + res = getattr(self, method)(*args, **kwargs) + return res # vim:sw=4:ts=4:et: diff --git a/runbullet/plugins/music/__init__.py b/runbullet/plugins/music/__init__.py index 652b1c8b..90f5f59e 100644 --- a/runbullet/plugins/music/__init__.py +++ b/runbullet/plugins/music/__init__.py @@ -1,34 +1,6 @@ from .. import Plugin class MusicPlugin(Plugin): - def run(self, args): - if 'clear' in args and args['clear']: - self.clear() - - if 'playlistadd' in args and args['playlistadd']: - self.playlistadd(args['playlistadd']) - - if 'add' in args and args['add']: - self.add(args['add']) - - if 'next' in args and args['next']: - self.next() - elif 'previous' in args and args['previous']: - self.previous() - - if 'setvol' in args and args['setvol']: - self.setvol(args['setvol']) - - status = self.status() - if 'play' in args and args['play'] and status['state'] != 'play': - self.play() - elif 'pause' in args and args['pause'] and status['state'] != 'pause': - self.pause() - elif 'stop' in args and args['stop']: - self.stop() - - return self.status() - def play(self): raise NotImplementedError() diff --git a/runbullet/plugins/shell/__init__.py b/runbullet/plugins/shell/__init__.py index 8143208c..a95e5d68 100644 --- a/runbullet/plugins/shell/__init__.py +++ b/runbullet/plugins/shell/__init__.py @@ -3,18 +3,12 @@ import subprocess from .. import Plugin class ShellPlugin(Plugin): - def run(self, args): - if 'cmd' not in args: - raise RuntimeError('No cmd parameter specified') - - cmd = args['cmd'] + def exec(self, cmd): output = None error = None try: - output = subprocess.check_output(cmd, - stderr=subprocess.STDOUT, - shell=True) + output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True) except subprocess.CalledProcessError as e: error = e.output diff --git a/runbullet/plugins/switch/__init__.py b/runbullet/plugins/switch/__init__.py index a968f1b8..00b59bc6 100644 --- a/runbullet/plugins/switch/__init__.py +++ b/runbullet/plugins/switch/__init__.py @@ -1,16 +1,6 @@ from .. import Plugin class SwitchPlugin(Plugin): - def run(self, args): - if 'on' in args and args['on']: - self.on(args) - elif 'off' in args and args['off']: - self.off(args) - elif 'toggle' in args and args['toggle']: - self.toggle(args) - - return self.status() - def on(self, args): raise NotImplementedError() diff --git a/runbullet/plugins/switch/wemo/__init__.py b/runbullet/plugins/switch/wemo/__init__.py index 13471268..fd810f74 100644 --- a/runbullet/plugins/switch/wemo/__init__.py +++ b/runbullet/plugins/switch/wemo/__init__.py @@ -17,19 +17,19 @@ class SwitchWemoPlugin(SwitchPlugin): logging.info('Starting WeMo discovery') self.env.discover(seconds=3) - def on(self, args): - switch = self.env.get_switch(args['device']) - logging.info('Turning {} on'.format(args['device'])) + def on(self, device): + switch = self.env.get_switch(device) + logging.info('Turning {} on'.format(device)) switch.on() - def off(self, args): - switch = self.env.get_switch(args['device']) - logging.info('Turning {} off'.format(args['device'])) + def off(self, device): + switch = self.env.get_switch(device) + logging.info('Turning {} off'.format(device)) switch.off() - def toggle(self, args): - switch = self.env.get_switch(args['device']) - logging.info('Toggling {}'.format(args['device'])) + def toggle(self, device): + switch = self.env.get_switch(device) + logging.info('Toggling {}'.format(device)) switch.toggle() def status(self):