fix: added a plugin::callback level mutex to avoid calling a callback while a previous call is still running

This commit is contained in:
Simone Margaritelli 2019-12-09 17:46:44 +02:00
parent ee6c06f306
commit 09a00adab9

View File

@ -1,6 +1,7 @@
import os import os
import glob import glob
import _thread import _thread
import threading
import importlib, importlib.util import importlib, importlib.util
import logging import logging
from pwnagotchi.ui import view from pwnagotchi.ui import view
@ -8,17 +9,27 @@ from pwnagotchi.ui import view
default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default") default_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "default")
loaded = {} loaded = {}
database = {} database = {}
locks = {}
class Plugin: class Plugin:
@classmethod @classmethod
def __init_subclass__(cls, **kwargs): def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs) super().__init_subclass__(**kwargs)
global loaded global loaded, locks
plugin_name = cls.__module__.split('.')[0] plugin_name = cls.__module__.split('.')[0]
plugin_instance = cls() plugin_instance = cls()
logging.debug("loaded plugin %s as %s" % (plugin_name, plugin_instance)) logging.debug("loaded plugin %s as %s" % (plugin_name, plugin_instance))
loaded[plugin_name] = plugin_instance loaded[plugin_name] = plugin_instance
for attr_name in plugin_instance.__dir__():
if attr_name.startswith('on_'):
cb = getattr(plugin_instance, attr_name, None)
if cb is not None and callable(cb):
locks["%s::%s" % (plugin_name, attr_name)] = threading.Lock()
def toggle_plugin(name, enable=True): def toggle_plugin(name, enable=True):
""" """
Load or unload a plugin Load or unload a plugin
@ -48,13 +59,15 @@ def on(event_name, *args, **kwargs):
def one(plugin_name, event_name, *args, **kwargs): def one(plugin_name, event_name, *args, **kwargs):
global loaded global loaded, locks
if plugin_name in loaded: if plugin_name in loaded:
plugin = loaded[plugin_name] plugin = loaded[plugin_name]
cb_name = 'on_%s' % event_name cb_name = 'on_%s' % event_name
callback = getattr(plugin, cb_name, None) callback = getattr(plugin, cb_name, None)
if callback is not None and callable(callback): if callback is not None and callable(callback):
try: try:
with locks["%s::%s" % (plugin_name, cb_name)]:
_thread.start_new_thread(callback, (*args, *kwargs)) _thread.start_new_thread(callback, (*args, *kwargs))
except Exception as e: except Exception as e:
logging.error("error while running %s.%s : %s" % (plugin_name, cb_name, e)) logging.error("error while running %s.%s : %s" % (plugin_name, cb_name, e))