Onionr/src/onionrplugins/__init__.py

272 lines
6.8 KiB
Python
Raw Normal View History

"""
Onionr - Private P2P Communication.
<anagement 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/>.
"""
2022-11-22 05:57:14 +00:00
import os, re
import importlib.util
import traceback
from . import onionrevents as events
2022-08-11 19:25:07 +00:00
from .pluginapis import plugin_apis
import config, logging
2019-07-15 03:01:56 +00:00
from utils import identifyhome
2019-07-22 23:59:48 +00:00
2019-03-29 03:33:14 +00:00
# set data dir
2019-07-15 03:01:56 +00:00
dataDir = identifyhome.identify_home()
_pluginsfolder = dataDir + 'plugins/'
2018-03-03 04:19:01 +00:00
_instances = dict()
2019-06-16 06:06:32 +00:00
config.reload()
2018-03-03 04:19:01 +00:00
2019-12-03 06:00:15 +00:00
def reload(stop_event = True):
"""
2018-03-03 04:19:01 +00:00
Reloads all the plugins
"""
2018-03-03 04:19:01 +00:00
check()
try:
enabled_plugins = get_enabled_plugins()
if stop_event is True:
logging.debug('Reloading all plugins...')
2018-03-03 04:19:01 +00:00
else:
logging.debug('Loading all plugins...')
2018-03-03 04:19:01 +00:00
if stop_event is True:
for plugin in enabled_plugins:
2019-12-03 06:00:15 +00:00
stop(plugin)
2018-03-03 04:19:01 +00:00
for plugin in enabled_plugins:
2019-12-03 06:00:15 +00:00
start(plugin)
2018-03-03 04:19:01 +00:00
return True
except:
logging.error('Failed to reload plugins.')
2018-03-03 04:19:01 +00:00
return False
2019-12-03 06:00:15 +00:00
def enable(name, start_event = True):
"""Enable a plugin."""
2018-03-03 04:19:01 +00:00
check()
if exists(name):
enabled_plugins = get_enabled_plugins()
if not name in enabled_plugins:
2018-07-02 21:08:47 +00:00
try:
2019-12-03 06:00:15 +00:00
events.call(get_plugin(name), 'enable')
2019-07-22 23:59:48 +00:00
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
2019-04-25 05:38:15 +00:00
# can happen inconsistently (especially between versions)
logging.error('Failed to enable module:')
logging.error(traceback.format_exc())
2018-07-02 21:08:47 +00:00
return False
else:
enabled_plugins.append(name)
2019-07-15 03:01:56 +00:00
config.set('plugins.enabled', enabled_plugins, savefile=True)
2018-07-02 21:08:47 +00:00
if start_event is True:
start(name)
return True
else:
return False
2018-03-03 04:19:01 +00:00
else:
logging.error('Failed to enable plugin \"%s\", disabling plugin.' % name)
logging.debug('Plugins folder not found: %s' % get_plugins_folder(str(name).lower()))
2018-03-03 04:19:01 +00:00
disable(name)
return False
2019-12-03 06:00:15 +00:00
def disable(name, stop_event = True):
"""
2018-03-03 04:19:01 +00:00
Disables a plugin
"""
2018-03-03 04:19:01 +00:00
check()
if is_enabled(name):
enabled_plugins = get_enabled_plugins()
enabled_plugins.remove(name)
2018-06-14 04:17:58 +00:00
config.set('plugins.enabled', enabled_plugins, True)
2018-03-03 04:19:01 +00:00
if exists(name):
2019-12-03 06:00:15 +00:00
events.call(get_plugin(name), 'disable')
2018-03-03 04:19:01 +00:00
if stop_event is True:
stop(name)
2019-12-03 06:00:15 +00:00
def start(name):
"""
2018-03-03 04:19:01 +00:00
Starts the plugin
"""
2018-03-03 04:19:01 +00:00
check()
if exists(name):
try:
plugin = get_plugin(name)
if plugin is None:
raise Exception('Failed to import module.')
else:
2019-12-03 06:00:15 +00:00
events.call(plugin, 'start')
2018-03-03 04:19:01 +00:00
return plugin
except:
logging.error('Failed to start module \"%s\".' % name)
2018-03-03 04:19:01 +00:00
else:
logging.error('Failed to start nonexistant module \"%s\".' % name)
2018-03-03 04:19:01 +00:00
return None
2019-12-03 06:00:15 +00:00
def stop(name):
"""
2018-03-03 04:19:01 +00:00
Stops the plugin
"""
2018-03-03 04:19:01 +00:00
check()
if exists(name):
try:
plugin = get_plugin(name)
if plugin is None:
raise Exception('Failed to import module.')
else:
2019-12-03 06:00:15 +00:00
events.call(plugin, 'stop')
2018-03-03 04:19:01 +00:00
return plugin
except:
logging.error('Failed to stop module \"%s\".' % name)
2018-03-03 04:19:01 +00:00
else:
logging.error('Failed to stop nonexistant module \"%s\".' % name)
2018-03-03 04:19:01 +00:00
return None
2019-03-29 03:33:14 +00:00
# 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)
2019-04-25 05:38:15 +00:00
module_name = module_dir # Module name must be unique otherwise it will get written in other imports
2019-03-29 03:33:14 +00:00
# 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
2018-03-03 04:19:01 +00:00
def get_plugin(name):
"""
2018-03-03 04:19:01 +00:00
Returns the instance of a module
"""
2018-03-03 04:19:01 +00:00
check()
if str(name).lower() in _instances:
return _instances[str(name).lower()]
else:
2019-04-25 05:38:15 +00:00
_instances[str(name).lower()] = import_module_from_file(get_plugins_folder(str(name).lower(), False) + 'main.py')
2018-03-03 04:19:01 +00:00
return get_plugin(name)
def get_plugins():
"""
2018-03-03 04:19:01 +00:00
Returns a list of plugins (deprecated)
"""
2018-03-03 04:19:01 +00:00
return _instances
def exists(name):
"""
2018-03-03 04:19:01 +00:00
Return value indicates whether or not the plugin exists
"""
2018-03-03 04:19:01 +00:00
return os.path.isdir(get_plugins_folder(str(name).lower()))
def get_enabled_plugins():
"""
2018-03-03 04:19:01 +00:00
Returns a list of the enabled plugins
"""
2018-03-03 04:19:01 +00:00
check()
config.reload()
2018-03-03 04:19:01 +00:00
2018-12-09 17:29:39 +00:00
return list(config.get('plugins.enabled', list()))
2018-03-03 04:19:01 +00:00
def is_enabled(name):
"""
2018-03-03 04:19:01 +00:00
Return value indicates whether or not the plugin is enabled
"""
2018-03-03 04:19:01 +00:00
return name in get_enabled_plugins()
def get_plugins_folder(name = None, absolute = True):
"""
2018-03-03 04:19:01 +00:00
Returns the path to the plugins folder
"""
2018-03-03 04:19:01 +00:00
path = ''
if name is None:
path = _pluginsfolder
else:
# only allow alphanumeric characters
2019-04-25 05:38:15 +00:00
#path = _pluginsfolder + str(name.lower())
2018-12-09 17:29:39 +00:00
path = _pluginsfolder + re.sub('[^0-9a-zA-Z_]+', '', str(name).lower())
2018-03-03 04:19:01 +00:00
if absolute is True:
path = os.path.abspath(path)
2018-04-23 03:42:37 +00:00
return path + '/'
def get_plugin_data_folder(name, absolute = True):
"""
2018-04-23 03:42:37 +00:00
Returns the location of a plugin's data folder
"""
2018-04-23 03:42:37 +00:00
2019-07-15 03:01:56 +00:00
return get_plugins_folder(name, absolute)
2018-03-03 04:19:01 +00:00
def check():
"""
2018-03-03 04:19:01 +00:00
Checks to make sure files exist
"""
2018-03-03 04:19:01 +00:00
if not config.is_set('plugins'):
logging.debug('Generating plugin configuration data...')
2018-03-03 04:19:01 +00:00
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
2018-03-03 04:19:01 +00:00
return