""" Onionr - Private P2P Communication. . """ import os, re import importlib.util import traceback from . import onionrevents as events from .pluginapis import plugin_apis import config, logging from utils import identifyhome # set data dir dataDir = identifyhome.identify_home() _pluginsfolder = dataDir + 'plugins/' _instances = dict() config.reload() def reload(stop_event = True): """ Reloads all the plugins """ check() try: enabled_plugins = get_enabled_plugins() if stop_event is True: logging.debug('Reloading all plugins...') else: logging.debug('Loading all plugins...') if stop_event is True: for plugin in enabled_plugins: stop(plugin) for plugin in enabled_plugins: start(plugin) return True except: logging.error('Failed to reload plugins.') return False def enable(name, start_event = True): """Enable a plugin.""" check() if exists(name): enabled_plugins = get_enabled_plugins() if not name in enabled_plugins: try: events.call(get_plugin(name), 'enable') except ImportError as e: # Was getting import error on Gitlab CI test "data" # NOTE: If you are experiencing issues with plugins not being enabled, it might be this resulting from an error in the module # can happen inconsistently (especially between versions) logging.error('Failed to enable module:') logging.error(traceback.format_exc()) return False else: enabled_plugins.append(name) config.set('plugins.enabled', enabled_plugins, savefile=True) if start_event is True: start(name) return True else: return False else: logging.error('Failed to enable plugin \"%s\", disabling plugin.' % name) logging.debug('Plugins folder not found: %s' % get_plugins_folder(str(name).lower())) disable(name) return False def disable(name, stop_event = True): """ Disables a plugin """ check() if is_enabled(name): enabled_plugins = get_enabled_plugins() enabled_plugins.remove(name) config.set('plugins.enabled', enabled_plugins, True) if exists(name): events.call(get_plugin(name), 'disable') if stop_event is True: stop(name) def start(name): """ Starts the plugin """ check() if exists(name): try: plugin = get_plugin(name) if plugin is None: raise Exception('Failed to import module.') else: events.call(plugin, 'start') return plugin except: logging.error('Failed to start module \"%s\".' % name) else: logging.error('Failed to start nonexistant module \"%s\".' % name) return None def stop(name): """ Stops the plugin """ check() if exists(name): try: plugin = get_plugin(name) if plugin is None: raise Exception('Failed to import module.') else: events.call(plugin, 'stop') return plugin except: logging.error('Failed to stop module \"%s\".' % name) else: logging.error('Failed to stop nonexistant module \"%s\".' % name) return None # credit: https://stackoverflow.com/a/29589414 def import_module_from_file(full_path_to_module): """ Import a module given the full path/filename of the .py file Python 3.4 """ module = None # Get module name and path from full path module_dir, module_file = os.path.split(full_path_to_module) module_name, module_ext = os.path.splitext(module_file) module_name = module_dir # Module name must be unique otherwise it will get written in other imports # Get module "spec" from filename spec = importlib.util.spec_from_file_location(module_name,full_path_to_module) module = spec.loader.load_module() return module def get_plugin(name): """ Returns the instance of a module """ check() if str(name).lower() in _instances: return _instances[str(name).lower()] else: _instances[str(name).lower()] = import_module_from_file(get_plugins_folder(str(name).lower(), False) + 'main.py') return get_plugin(name) def get_plugins(): """ Returns a list of plugins (deprecated) """ return _instances def exists(name): """ Return value indicates whether or not the plugin exists """ return os.path.isdir(get_plugins_folder(str(name).lower())) def get_enabled_plugins(): """ Returns a list of the enabled plugins """ check() config.reload() return list(config.get('plugins.enabled', list())) def is_enabled(name): """ Return value indicates whether or not the plugin is enabled """ return name in get_enabled_plugins() def get_plugins_folder(name = None, absolute = True): """ Returns the path to the plugins folder """ path = '' if name is None: path = _pluginsfolder else: # only allow alphanumeric characters #path = _pluginsfolder + str(name.lower()) path = _pluginsfolder + re.sub('[^0-9a-zA-Z_]+', '', str(name).lower()) if absolute is True: path = os.path.abspath(path) return path + '/' def get_plugin_data_folder(name, absolute = True): """ Returns the location of a plugin's data folder """ return get_plugins_folder(name, absolute) def check(): """ Checks to make sure files exist """ if not config.is_set('plugins'): logging.debug('Generating plugin configuration data...') config.set('plugins', {'enabled': []}, True) if not os.path.exists(os.path.dirname(get_plugins_folder())): logging.debug('Generating plugin data folder...') try: os.makedirs(os.path.dirname(get_plugins_folder())) except FileExistsError: pass return