2018-03-03 04:19:01 +00:00
|
|
|
'''
|
|
|
|
Onionr - P2P Microblogging Platform & Social network
|
|
|
|
|
|
|
|
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, config, logger
|
|
|
|
import onionrevents as events
|
|
|
|
|
2019-03-28 19:08:07 +00:00
|
|
|
# set data dir
|
|
|
|
dataDir = os.environ.get('ONIONR_HOME', os.environ.get('DATA_DIR', 'data/'))
|
|
|
|
if not dataDir.endswith('/'):
|
|
|
|
dataDir += '/'
|
2018-09-26 04:58:11 +00:00
|
|
|
|
|
|
|
_pluginsfolder = dataDir + 'plugins/'
|
2018-03-03 04:19:01 +00:00
|
|
|
_instances = dict()
|
|
|
|
|
2018-04-21 01:20:26 +00:00
|
|
|
def reload(onionr = None, stop_event = True):
|
2018-03-03 04:19:01 +00:00
|
|
|
'''
|
|
|
|
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:
|
2018-04-21 01:20:26 +00:00
|
|
|
stop(plugin, onionr)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
for plugin in enabled_plugins:
|
2018-04-21 01:20:26 +00:00
|
|
|
start(plugin, onionr)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
except:
|
|
|
|
logger.error('Failed to reload plugins.')
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
2018-04-21 01:20:26 +00:00
|
|
|
def enable(name, onionr = None, start_event = True):
|
2018-03-03 04:19:01 +00:00
|
|
|
'''
|
|
|
|
Enables a plugin
|
|
|
|
'''
|
|
|
|
|
|
|
|
check()
|
|
|
|
|
|
|
|
if exists(name):
|
|
|
|
enabled_plugins = get_enabled_plugins()
|
2018-05-14 04:22:28 +00:00
|
|
|
if not name in enabled_plugins:
|
2018-07-02 21:08:47 +00:00
|
|
|
try:
|
|
|
|
events.call(get_plugin(name), 'enable', onionr)
|
2019-03-31 00:25:07 +00:00
|
|
|
except ImportError as e: # Was getting import error on Gitlab CI test "data"
|
2019-03-06 22:39:46 +00:00
|
|
|
# NOTE: If you are experiencing issues with plugins not being enabled, it might be this resulting from an error in the module
|
|
|
|
# can happen inconsistenly (especially between versions)
|
2019-03-31 00:25:07 +00:00
|
|
|
logger.debug('Failed to enable module; Import error: %s' % e)
|
2018-07-02 21:08:47 +00:00
|
|
|
return False
|
|
|
|
else:
|
|
|
|
enabled_plugins.append(name)
|
|
|
|
config.set('plugins.enabled', enabled_plugins, True)
|
2018-11-11 03:25:40 +00:00
|
|
|
|
2018-07-02 21:08:47 +00:00
|
|
|
if start_event is True:
|
|
|
|
start(name)
|
|
|
|
return True
|
2018-05-14 04:22:28 +00:00
|
|
|
else:
|
|
|
|
return False
|
2018-03-03 04:19:01 +00:00
|
|
|
else:
|
2019-03-31 00:25:07 +00:00
|
|
|
logger.error('Failed to enable plugin \"%s\" (disabling plugin).' % name)
|
|
|
|
logger.debug('Plugins folder not found: %s' % get_plugins_folder(str(name).lower()))
|
2018-03-03 04:19:01 +00:00
|
|
|
disable(name)
|
|
|
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
2018-04-21 01:20:26 +00:00
|
|
|
def disable(name, onionr = None, stop_event = True):
|
2018-03-03 04:19:01 +00:00
|
|
|
'''
|
|
|
|
Disables a plugin
|
|
|
|
'''
|
|
|
|
|
|
|
|
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):
|
2018-04-21 01:20:26 +00:00
|
|
|
events.call(get_plugin(name), 'disable', onionr)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
if stop_event is True:
|
|
|
|
stop(name)
|
|
|
|
|
2018-04-21 01:20:26 +00:00
|
|
|
def start(name, onionr = None):
|
2018-03-03 04:19:01 +00:00
|
|
|
'''
|
|
|
|
Starts the plugin
|
|
|
|
'''
|
|
|
|
|
|
|
|
check()
|
|
|
|
|
|
|
|
if exists(name):
|
|
|
|
try:
|
|
|
|
plugin = get_plugin(name)
|
|
|
|
|
|
|
|
if plugin is None:
|
|
|
|
raise Exception('Failed to import module.')
|
|
|
|
else:
|
2018-04-21 01:20:26 +00:00
|
|
|
events.call(plugin, 'start', onionr)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
return plugin
|
|
|
|
except:
|
2018-06-01 04:25:28 +00:00
|
|
|
logger.error('Failed to start module \"%s\".' % name)
|
2018-03-03 04:19:01 +00:00
|
|
|
else:
|
2018-06-01 04:25:28 +00:00
|
|
|
logger.error('Failed to start nonexistant module \"%s\".' % name)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
return None
|
|
|
|
|
2018-04-21 01:20:26 +00:00
|
|
|
def stop(name, onionr = None):
|
2018-03-03 04:19:01 +00:00
|
|
|
'''
|
|
|
|
Stops the plugin
|
|
|
|
'''
|
|
|
|
|
|
|
|
check()
|
|
|
|
|
|
|
|
if exists(name):
|
|
|
|
try:
|
|
|
|
plugin = get_plugin(name)
|
|
|
|
|
|
|
|
if plugin is None:
|
|
|
|
raise Exception('Failed to import module.')
|
|
|
|
else:
|
2018-04-21 01:20:26 +00:00
|
|
|
events.call(plugin, 'stop', onionr)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
return plugin
|
|
|
|
except:
|
2018-06-01 04:25:28 +00:00
|
|
|
logger.error('Failed to stop module \"%s\".' % name)
|
2018-03-03 04:19:01 +00:00
|
|
|
else:
|
2018-06-01 04:25:28 +00:00
|
|
|
logger.error('Failed to stop nonexistant module \"%s\".' % name)
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
return None
|
|
|
|
|
2019-03-29 03:25:20 +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)
|
|
|
|
|
|
|
|
# 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):
|
|
|
|
'''
|
|
|
|
Returns the instance of a module
|
|
|
|
'''
|
|
|
|
|
|
|
|
check()
|
|
|
|
|
|
|
|
if str(name).lower() in _instances:
|
|
|
|
return _instances[str(name).lower()]
|
|
|
|
else:
|
2019-03-29 03:25:20 +00:00
|
|
|
_instances[str(name).lower()] = import_module_from_file(get_plugins_folder(name, False) + 'main.py')
|
2018-03-03 04:19:01 +00:00
|
|
|
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()
|
|
|
|
|
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):
|
|
|
|
'''
|
|
|
|
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
|
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):
|
|
|
|
'''
|
|
|
|
Returns the location of a plugin's data folder
|
|
|
|
'''
|
|
|
|
|
2018-09-26 04:58:11 +00:00
|
|
|
return get_plugins_folder(name, absolute) + dataDir
|
2018-03-03 04:19:01 +00:00
|
|
|
|
|
|
|
def check():
|
|
|
|
'''
|
|
|
|
Checks to make sure files exist
|
|
|
|
'''
|
|
|
|
|
|
|
|
config.reload()
|
|
|
|
|
|
|
|
if not config.is_set('plugins'):
|
2018-11-11 03:25:40 +00:00
|
|
|
logger.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())):
|
|
|
|
logger.debug('Generating plugin data folder...')
|
2018-03-03 22:18:57 +00:00
|
|
|
os.makedirs(os.path.dirname(get_plugins_folder()))
|
2018-04-21 03:10:50 +00:00
|
|
|
|
2018-03-03 04:19:01 +00:00
|
|
|
return
|