renamed onionr dir and bugfixes/linting progress
This commit is contained in:
		
							parent
							
								
									2b996da17f
								
							
						
					
					
						commit
						720efe4fca
					
				
					 226 changed files with 179 additions and 142 deletions
				
			
		
							
								
								
									
										269
									
								
								src/onionrplugins/__init__.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										269
									
								
								src/onionrplugins/__init__.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,269 @@ | |||
| ''' | ||||
|     Onionr - Private P2P Communication | ||||
| 
 | ||||
|     This file deals with management of modules/plugins. | ||||
| ''' | ||||
| ''' | ||||
|     This program is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation, either version 3 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
| ''' | ||||
| import os, re, importlib | ||||
| 
 | ||||
| from . import onionrevents as events | ||||
| import config, logger | ||||
| from utils import identifyhome | ||||
| 
 | ||||
| # set data dir | ||||
| dataDir = identifyhome.identify_home() | ||||
| 
 | ||||
| _pluginsfolder = dataDir + 'plugins/' | ||||
| _instances = dict() | ||||
| config.reload() | ||||
| 
 | ||||
| def reload(onionr = None, stop_event = True): | ||||
|     ''' | ||||
|         Reloads all the plugins | ||||
|     ''' | ||||
| 
 | ||||
|     check() | ||||
| 
 | ||||
|     try: | ||||
|         enabled_plugins = get_enabled_plugins() | ||||
| 
 | ||||
|         if stop_event is True: | ||||
|             logger.debug('Reloading all plugins...') | ||||
|         else: | ||||
|             logger.debug('Loading all plugins...') | ||||
| 
 | ||||
|         if stop_event is True: | ||||
|             for plugin in enabled_plugins: | ||||
|                 stop(plugin, onionr) | ||||
| 
 | ||||
|         for plugin in enabled_plugins: | ||||
|             start(plugin, onionr) | ||||
| 
 | ||||
|         return True | ||||
|     except: | ||||
|         logger.error('Failed to reload plugins.') | ||||
| 
 | ||||
|     return False | ||||
| 
 | ||||
| def enable(name, onionr = None, start_event = True): | ||||
|     ''' | ||||
|         Enables a plugin | ||||
|     ''' | ||||
| 
 | ||||
|     check() | ||||
| 
 | ||||
|     if exists(name): | ||||
|         enabled_plugins = get_enabled_plugins() | ||||
|         if not name in enabled_plugins: | ||||
|             try: | ||||
|                 events.call(get_plugin(name), 'enable', onionr) | ||||
|             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) | ||||
|                 logger.debug('Failed to enable module; Import error: %s' % e) | ||||
|                 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: | ||||
|         logger.error('Failed to enable plugin \"%s\", disabling plugin.' % name, terminal=True) | ||||
|         logger.debug('Plugins folder not found: %s' % get_plugins_folder(str(name).lower())) | ||||
|         disable(name) | ||||
| 
 | ||||
|         return False | ||||
| 
 | ||||
| 
 | ||||
| def disable(name, onionr = None, 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', onionr) | ||||
| 
 | ||||
|         if stop_event is True: | ||||
|             stop(name) | ||||
| 
 | ||||
| def start(name, onionr = None): | ||||
|     ''' | ||||
|         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', onionr) | ||||
| 
 | ||||
|             return plugin | ||||
|         except: | ||||
|             logger.error('Failed to start module \"%s\".' % name) | ||||
|     else: | ||||
|         logger.error('Failed to start nonexistant module \"%s\".' % name) | ||||
| 
 | ||||
|     return None | ||||
| 
 | ||||
| def stop(name, onionr = None): | ||||
|     ''' | ||||
|         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', onionr) | ||||
| 
 | ||||
|             return plugin | ||||
|         except: | ||||
|             logger.error('Failed to stop module \"%s\".' % name) | ||||
|     else: | ||||
|         logger.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() | ||||
| 
 | ||||
|     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'): | ||||
|         logger.debug('Generating plugin configuration data...') | ||||
|         config.set('plugins', {'enabled': []}, True) | ||||
| 
 | ||||
|     if not os.path.exists(os.path.dirname(get_plugins_folder())): | ||||
|         logger.debug('Generating plugin data folder...') | ||||
|         try: | ||||
|             os.makedirs(os.path.dirname(get_plugins_folder())) | ||||
|         except FileExistsError: | ||||
|             pass | ||||
|     return | ||||
							
								
								
									
										75
									
								
								src/onionrplugins/onionrevents.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										75
									
								
								src/onionrplugins/onionrevents.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,75 @@ | |||
| ''' | ||||
|     Onionr - Private P2P Communication | ||||
| 
 | ||||
|     This file deals with configuration management. | ||||
| ''' | ||||
| ''' | ||||
|     This program is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation, either version 3 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
| ''' | ||||
| from threading import Thread | ||||
| 
 | ||||
| import config, logger | ||||
| import onionrplugins as plugins | ||||
| from . import onionrpluginapi as pluginapi | ||||
| 
 | ||||
| 
 | ||||
| def get_pluginapi(data): | ||||
|     return pluginapi.SharedAPI(data) | ||||
| 
 | ||||
| def __event_caller(event_name, data = {}): | ||||
|     ''' | ||||
|         DO NOT call this function, this is for threading code only. | ||||
|         Instead, call onionrevents.event | ||||
|     ''' | ||||
|     for plugin in plugins.get_enabled_plugins(): | ||||
|         try: | ||||
|             call(plugins.get_plugin(plugin), event_name, data, get_pluginapi(data)) | ||||
|         except ModuleNotFoundError as e: | ||||
|             logger.warn('Disabling nonexistant plugin "%s"...' % plugin, terminal=True) | ||||
|             plugins.disable(plugin, stop_event = False) | ||||
|         except Exception as e: | ||||
|             logger.warn('Event "%s" failed for plugin "%s".' % (event_name, plugin), terminal=True) | ||||
|             logger.debug(str(e), terminal=True) | ||||
| 
 | ||||
| def event(event_name, data = {}, threaded = True): | ||||
|     ''' | ||||
|         Calls an event on all plugins (if defined) | ||||
|     ''' | ||||
| 
 | ||||
|     if threaded: | ||||
|         thread = Thread(target = __event_caller, args = (event_name, data)) | ||||
|         thread.start() | ||||
|         return thread | ||||
|     else: | ||||
|         __event_caller(event_name, data) | ||||
| 
 | ||||
| def call(plugin, event_name, data = None, pluginapi = None): | ||||
|     ''' | ||||
|         Calls an event on a plugin if one is defined | ||||
|     ''' | ||||
| 
 | ||||
|     if not plugin is None: | ||||
|         try: | ||||
|             attribute = 'on_' + str(event_name).lower() | ||||
|             if pluginapi is None: | ||||
|                 pluginapi = get_pluginapi(data) | ||||
|             if hasattr(plugin, attribute): | ||||
|                 return getattr(plugin, attribute)(pluginapi, data) | ||||
| 
 | ||||
|             return True | ||||
|         except Exception as e: | ||||
|             #logger.error(str(e), terminal=True) | ||||
|             return False | ||||
|     else: | ||||
|         return True | ||||
							
								
								
									
										81
									
								
								src/onionrplugins/onionrpluginapi.py
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										81
									
								
								src/onionrplugins/onionrpluginapi.py
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| ''' | ||||
|     Onionr - Private P2P Communication | ||||
| 
 | ||||
|     This file deals with the object that is passed with each event | ||||
| ''' | ||||
| ''' | ||||
|     This program is free software: you can redistribute it and/or modify | ||||
|     it under the terms of the GNU General Public License as published by | ||||
|     the Free Software Foundation, either version 3 of the License, or | ||||
|     (at your option) any later version. | ||||
| 
 | ||||
|     This program is distributed in the hope that it will be useful, | ||||
|     but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|     GNU General Public License for more details. | ||||
| 
 | ||||
|     You should have received a copy of the GNU General Public License | ||||
|     along with this program.  If not, see <https://www.gnu.org/licenses/>. | ||||
| ''' | ||||
| 
 | ||||
| import onionrplugins, logger | ||||
| from onionrutils import localcommand | ||||
| from coredb import daemonqueue | ||||
| 
 | ||||
| class PluginAPI: | ||||
|     def __init__(self, pluginapi): | ||||
|         self.pluginapi = pluginapi | ||||
| 
 | ||||
|     def start(self, name): | ||||
|         onionrplugins.start(name) | ||||
| 
 | ||||
|     def stop(self, name): | ||||
|         onionrplugins.stop(name) | ||||
| 
 | ||||
|     def reload(self, name): | ||||
|         onionrplugins.reload(name) | ||||
| 
 | ||||
|     def enable(self, name): | ||||
|         onionrplugins.enable(name) | ||||
| 
 | ||||
|     def disable(self, name): | ||||
|         onionrplugins.disable(name) | ||||
| 
 | ||||
|     def event(self, name, data = {}): | ||||
|         events.event(name, data = data) | ||||
| 
 | ||||
|     def is_enabled(self, name): | ||||
|         return onionrplugins.is_enabled(name) | ||||
| 
 | ||||
|     def get_enabled_plugins(self): | ||||
|         return onionrplugins.get_enabled() | ||||
| 
 | ||||
|     def get_folder(self, name = None, absolute = True): | ||||
|         return onionrplugins.get_plugins_folder(name = name, absolute = absolute) | ||||
| 
 | ||||
|     def get_data_folder(self, name, absolute = True): | ||||
|         return onionrplugins.get_plugin_data_folder(name, absolute = absolute) | ||||
| 
 | ||||
|     def daemon_event(self, event, plugin = None): | ||||
|         return # later make local command like /client/?action=makeEvent&event=eventname&module=modulename | ||||
| 
 | ||||
| class CommandAPI: | ||||
|     def __init__(self, pluginapi): | ||||
|         self.pluginapi = pluginapi | ||||
| 
 | ||||
|     def call(self, name): | ||||
|         self.pluginapi.get_onionr().execute(name) | ||||
| 
 | ||||
| class SharedAPI: | ||||
|     def __init__(self, data): | ||||
|         self.data = data | ||||
|         self.plugins = PluginAPI(self) | ||||
| 
 | ||||
|     def get_data(self): | ||||
|         return self.data | ||||
| 
 | ||||
|     def get_daemonapi(self): | ||||
|         return self.daemon | ||||
| 
 | ||||
|     def get_pluginapi(self): | ||||
|         return self.plugins | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue