turn classmethod 'find_all_plugins' into an instance method.
change 'use_' prefix to 'enable_plugin_'
This commit is contained in:
@@ -57,7 +57,6 @@ class Plugins(DaemonThread):
|
|||||||
|
|
||||||
LOGGING_SHORTCUT = 'p'
|
LOGGING_SHORTCUT = 'p'
|
||||||
pkgpath = os.path.dirname(plugins.__file__)
|
pkgpath = os.path.dirname(plugins.__file__)
|
||||||
_all_found_plugins = None # type: Optional[Dict[str, dict]]
|
|
||||||
|
|
||||||
@profiler
|
@profiler
|
||||||
def __init__(self, config: SimpleConfig, gui_name):
|
def __init__(self, config: SimpleConfig, gui_name):
|
||||||
@@ -66,48 +65,44 @@ class Plugins(DaemonThread):
|
|||||||
self.config = config
|
self.config = config
|
||||||
self.hw_wallets = {}
|
self.hw_wallets = {}
|
||||||
self.plugins = {} # type: Dict[str, BasePlugin]
|
self.plugins = {} # type: Dict[str, BasePlugin]
|
||||||
|
self.internal_plugin_metadata = {}
|
||||||
self.gui_name = gui_name
|
self.gui_name = gui_name
|
||||||
self.descriptions = {}
|
|
||||||
self.device_manager = DeviceMgr(config)
|
self.device_manager = DeviceMgr(config)
|
||||||
|
self.find_internal_plugins()
|
||||||
self.load_plugins()
|
self.load_plugins()
|
||||||
self.add_jobs(self.device_manager.thread_jobs())
|
self.add_jobs(self.device_manager.thread_jobs())
|
||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
@classmethod
|
@property
|
||||||
def find_all_plugins(cls) -> Mapping[str, dict]:
|
def descriptions(self):
|
||||||
"""Return a map of all found plugins: name -> description.
|
return dict(list(self.internal_plugin_metadata.items()))
|
||||||
Note that plugins not available for the current GUI are also included.
|
|
||||||
"""
|
|
||||||
if cls._all_found_plugins is None:
|
|
||||||
cls._all_found_plugins = dict()
|
|
||||||
iter_modules = list(pkgutil.iter_modules([cls.pkgpath]))
|
|
||||||
for loader, name, ispkg in iter_modules:
|
|
||||||
# FIXME pyinstaller binaries are packaging each built-in plugin twice:
|
|
||||||
# once as data and once as code. To honor the "no duplicates" rule below,
|
|
||||||
# we exclude the ones packaged as *code*, here:
|
|
||||||
if loader.__class__.__qualname__ == "FrozenImporter":
|
|
||||||
continue
|
|
||||||
full_name = f'electrum.plugins.{name}'
|
|
||||||
spec = importlib.util.find_spec(full_name)
|
|
||||||
if spec is None: # pkgutil found it but importlib can't ?!
|
|
||||||
raise Exception(f"Error pre-loading {full_name}: no spec")
|
|
||||||
try:
|
|
||||||
module = importlib.util.module_from_spec(spec)
|
|
||||||
# sys.modules needs to be modified for relative imports to work
|
|
||||||
# see https://stackoverflow.com/a/50395128
|
|
||||||
sys.modules[spec.name] = module
|
|
||||||
spec.loader.exec_module(module)
|
|
||||||
except Exception as e:
|
|
||||||
raise Exception(f"Error pre-loading {full_name}: {repr(e)}") from e
|
|
||||||
d = module.__dict__
|
|
||||||
if name in cls._all_found_plugins:
|
|
||||||
_logger.info(f"Found the following plugin modules: {iter_modules=}")
|
|
||||||
raise Exception(f"duplicate plugins? for {name=}")
|
|
||||||
cls._all_found_plugins[name] = d
|
|
||||||
return cls._all_found_plugins
|
|
||||||
|
|
||||||
def load_plugins(self):
|
def find_internal_plugins(self) -> Mapping[str, dict]:
|
||||||
for name, d in self.find_all_plugins().items():
|
"""Populates self.internal_plugin_metadata
|
||||||
|
"""
|
||||||
|
iter_modules = list(pkgutil.iter_modules([self.pkgpath]))
|
||||||
|
for loader, name, ispkg in iter_modules:
|
||||||
|
# FIXME pyinstaller binaries are packaging each built-in plugin twice:
|
||||||
|
# once as data and once as code. To honor the "no duplicates" rule below,
|
||||||
|
# we exclude the ones packaged as *code*, here:
|
||||||
|
if loader.__class__.__qualname__ == "FrozenImporter":
|
||||||
|
continue
|
||||||
|
full_name = f'electrum.plugins.{name}'
|
||||||
|
spec = importlib.util.find_spec(full_name)
|
||||||
|
if spec is None: # pkgutil found it but importlib can't ?!
|
||||||
|
raise Exception(f"Error pre-loading {full_name}: no spec")
|
||||||
|
try:
|
||||||
|
module = importlib.util.module_from_spec(spec)
|
||||||
|
# sys.modules needs to be modified for relative imports to work
|
||||||
|
# see https://stackoverflow.com/a/50395128
|
||||||
|
sys.modules[spec.name] = module
|
||||||
|
spec.loader.exec_module(module)
|
||||||
|
except Exception as e:
|
||||||
|
raise Exception(f"Error pre-loading {full_name}: {repr(e)}") from e
|
||||||
|
d = module.__dict__
|
||||||
|
if 'fullname' not in d:
|
||||||
|
continue
|
||||||
|
d['display_name'] = d['fullname']
|
||||||
gui_good = self.gui_name in d.get('available_for', [])
|
gui_good = self.gui_name in d.get('available_for', [])
|
||||||
if not gui_good:
|
if not gui_good:
|
||||||
continue
|
continue
|
||||||
@@ -117,8 +112,20 @@ class Plugins(DaemonThread):
|
|||||||
details = d.get('registers_keystore')
|
details = d.get('registers_keystore')
|
||||||
if details:
|
if details:
|
||||||
self.register_keystore(name, gui_good, details)
|
self.register_keystore(name, gui_good, details)
|
||||||
self.descriptions[name] = d
|
if d.get('requires_wallet_type'):
|
||||||
if not d.get('requires_wallet_type') and self.config.get('use_' + name):
|
# trustedcoin will not be added to list
|
||||||
|
continue
|
||||||
|
if name in self.internal_plugin_metadata:
|
||||||
|
_logger.info(f"Found the following plugin modules: {iter_modules=}")
|
||||||
|
raise Exception(f"duplicate plugins? for {name=}")
|
||||||
|
self.internal_plugin_metadata[name] = d
|
||||||
|
|
||||||
|
def load_plugins(self):
|
||||||
|
self.load_internal_plugins()
|
||||||
|
|
||||||
|
def load_internal_plugins(self):
|
||||||
|
for name, d in self.internal_plugin_metadata.items():
|
||||||
|
if self.config.get('enable_plugin_' + name) is True:
|
||||||
try:
|
try:
|
||||||
self.load_plugin(name)
|
self.load_plugin(name)
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
@@ -156,14 +163,14 @@ class Plugins(DaemonThread):
|
|||||||
self.remove_jobs(plugin.thread_jobs())
|
self.remove_jobs(plugin.thread_jobs())
|
||||||
|
|
||||||
def enable(self, name: str) -> 'BasePlugin':
|
def enable(self, name: str) -> 'BasePlugin':
|
||||||
self.config.set_key('use_' + name, True, save=True)
|
self.config.set_key('enable_plugin_' + name, True, save=True)
|
||||||
p = self.get(name)
|
p = self.get(name)
|
||||||
if p:
|
if p:
|
||||||
return p
|
return p
|
||||||
return self.load_plugin(name)
|
return self.load_plugin(name)
|
||||||
|
|
||||||
def disable(self, name: str) -> None:
|
def disable(self, name: str) -> None:
|
||||||
self.config.set_key('use_' + name, False, save=True)
|
self.config.set_key('enable_plugin_' + name, False, save=True)
|
||||||
p = self.get(name)
|
p = self.get(name)
|
||||||
if not p:
|
if not p:
|
||||||
return
|
return
|
||||||
@@ -173,12 +180,7 @@ class Plugins(DaemonThread):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_plugin_enabler_config_key(cls, key: str) -> bool:
|
def is_plugin_enabler_config_key(cls, key: str) -> bool:
|
||||||
if not key.startswith('use_'):
|
return key.startswith('enable_plugin_')
|
||||||
return False
|
|
||||||
# note: the 'use_' prefix is not sufficient to check, there are
|
|
||||||
# non-plugin-related config keys that also have it... hence:
|
|
||||||
name = key[4:]
|
|
||||||
return name in cls.find_all_plugins()
|
|
||||||
|
|
||||||
def toggle(self, name: str) -> Optional['BasePlugin']:
|
def toggle(self, name: str) -> Optional['BasePlugin']:
|
||||||
p = self.get(name)
|
p = self.get(name)
|
||||||
@@ -204,7 +206,7 @@ class Plugins(DaemonThread):
|
|||||||
if gui_good:
|
if gui_good:
|
||||||
try:
|
try:
|
||||||
p = self.get_plugin(name)
|
p = self.get_plugin(name)
|
||||||
if p.is_enabled():
|
if p.is_available():
|
||||||
out.append(HardwarePluginToScan(name=name,
|
out.append(HardwarePluginToScan(name=name,
|
||||||
description=details[2],
|
description=details[2],
|
||||||
plugin=p,
|
plugin=p,
|
||||||
@@ -276,7 +278,7 @@ class BasePlugin(Logger):
|
|||||||
self.parent = parent # type: Plugins # The plugins object
|
self.parent = parent # type: Plugins # The plugins object
|
||||||
self.name = name
|
self.name = name
|
||||||
self.config = config
|
self.config = config
|
||||||
self.wallet = None
|
self.wallet = None # fixme: this field should not exist
|
||||||
Logger.__init__(self)
|
Logger.__init__(self)
|
||||||
# add self to hooks
|
# add self to hooks
|
||||||
for k in dir(self):
|
for k in dir(self):
|
||||||
@@ -313,7 +315,7 @@ class BasePlugin(Logger):
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
def is_enabled(self):
|
def is_enabled(self):
|
||||||
return self.is_available() and self.config.get('use_'+self.name) is True
|
return self.is_available() and self.config.get('enable_plugin_'+self.name) is True
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self):
|
||||||
return True
|
return True
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ Submarine swap server for an Electrum daemon.
|
|||||||
|
|
||||||
Example setup:
|
Example setup:
|
||||||
|
|
||||||
electrum -o setconfig use_swapserver True
|
electrum -o setconfig enable_plugin_swapserver True
|
||||||
electrum -o setconfig swapserver_port 5455
|
electrum -o setconfig swapserver_port 5455
|
||||||
electrum daemon -v
|
electrum daemon -v
|
||||||
|
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ class TestLightningSwapserver(TestLightning):
|
|||||||
},
|
},
|
||||||
'bob': {
|
'bob': {
|
||||||
'lightning_listen': 'localhost:9735',
|
'lightning_listen': 'localhost:9735',
|
||||||
'use_swapserver': 'true',
|
'enable_plugin_swapserver': 'true',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user