Major rewrite for more modularity and maintanability

This commit is contained in:
Fabio Manganiello 2017-11-03 04:08:47 +01:00
parent 13023b660e
commit bbb8bd9020
6 changed files with 136 additions and 24 deletions

View file

@ -1,4 +1,30 @@
import os
import sys
import yaml
class Plugin(object): class Plugin(object):
def __init__(self):
for cls in reversed(self.__class__.mro()):
if cls is not object:
try:
cls._init(self)
except AttributeError as e:
pass
def _init(self):
module_dir = os.path.dirname(sys.modules[self.__module__].__file__)
config_file = module_dir + os.sep + 'config.yaml'
config = {}
try:
with open(config_file, 'r') as f:
self.config = yaml.load(f)
except FileNotFoundError as e:
pass
def run(self, args): def run(self, args):
raise NotImplementedError() raise NotImplementedError()

View file

@ -0,0 +1,28 @@
from .. import Plugin
class MusicPlugin(Plugin):
def run(self, args):
if 'play' in args and self.status()['state'] != 'play':
self.play()
elif 'pause' in args and self.status()['state'] != 'pause':
self.pause()
elif 'stop' in args:
self.stop()
return self.status()
def play(self):
raise NotImplementedError()
def pause(self):
raise NotImplementedError()
def stop(self):
raise NotImplementedError()
def status(self):
raise NotImplementedError()
# vim:sw=4:ts=4:et:

View file

@ -0,0 +1,23 @@
import mpd
from .. import MusicPlugin
class MusicMpdPlugin(MusicPlugin):
def _init(self):
self.client = mpd.MPDClient(use_unicode=True)
self.client.connect(self.config['host'], self.config['port'])
def play(self):
self.client.play()
def pause(self):
self.client.pause()
def stop(self):
self.client.stop()
def status(self):
return self.client.status()
# vim:sw=4:ts=4:et:

View file

@ -0,0 +1,6 @@
host: localhost
port: 6600
_deps:
- python-mpd2

View file

@ -18,7 +18,7 @@ class ShellPlugin(Plugin):
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError as e:
error = e.output error = e.output
return output, error return [output, error]
# vim:sw=4:ts=4:et: # vim:sw=4:ts=4:et:

View file

@ -50,38 +50,67 @@ def on_error(ws, error):
logging.error(error) logging.error(error)
def _exec_func(body): def _init_plugin(plugin, reload=False):
module_name = 'plugins.{}'.format(body['plugin']) module_name = 'plugins.{}'.format(plugin)
if module_name in modules: if module_name not in modules or reload:
module = modules[module_name]
else:
try: try:
module = importlib.import_module(module_name) modules[module_name] = importlib.import_module(module_name)
modules[module_name] = module
except ModuleNotFoundError as e: except ModuleNotFoundError as e:
logging.warn('No such plugin: {}'.format(body['plugin'])) logging.warn('No such plugin: {}'.format(plugin))
return raise RuntimeError(e)
logging.info('Received push addressed to me: {}'.format(body))
args = body['args'] if 'args' in body else {}
cls_name = functools.reduce( cls_name = functools.reduce(
lambda a,b: a.title() + b.title(), lambda a,b: a.title() + b.title(),
(body['plugin'].title().split('.')) (plugin.title().split('.'))
) + 'Plugin' ) + 'Plugin'
if cls_name in plugins: if cls_name not in plugins or reload:
instance = plugins[cls_name] try:
else: plugins[cls_name] = getattr(modules[module_name], cls_name)()
cls = getattr(module, cls_name) except AttributeError as e:
instance = cls() logging.warn('No such class in {}: {}'.format(
plugins[cls_name] = cls module_name, cls_name))
raise RuntimeError(e)
out, err = instance.run(args) return plugins[cls_name]
def _exec_func(body, retry=True):
try:
logging.info('Received push addressed to me: {}'.format(body))
args = body['args'] if 'args' in body else {}
if 'plugin' not in body:
logging.warn('No plugin specified')
return
plugin_name = body['plugin']
try:
plugin = _init_plugin(plugin_name)
except RuntimeError as e: # Module/class not found
return
ret = plugin.run(args)
out = None
err = None
if isinstance(ret, list):
out = ret[0]
err = ret[1] if len(ret) > 1 else None
elif ret is not None:
out = ret
if out:
logging.info('Command output: {}'.format(out)) logging.info('Command output: {}'.format(out))
if err: if err:
logging.warn('Command error: {}'.format(err)) logging.warn('Command error: {}'.format(err))
except Exception as e:
logging.exception(e)
if retry:
logging.info('Reloading plugin {} and retrying'.format(plugin_name))
_init_plugin(plugin_name, reload=True)
_exec_func(body, retry=False)
def _on_push(ws, data): def _on_push(ws, data):