1
0

qml: simplify QEConfig and QEDaemon use.

force QEDaemon singleton, and refer to QEDaemon.instance where possible
In cases where we would run into circular dependencies, pass the instance

also refer to singleton QEConfig instead of passing instance in qeapp.py
This commit is contained in:
Sander van Grieken
2025-04-09 13:44:26 +02:00
parent 96793d6e43
commit eb29b7c95c
5 changed files with 36 additions and 34 deletions

View File

@@ -82,7 +82,7 @@ class ElectrumGui(BaseElectrumGui, Logger):
self.timer.timeout.connect(lambda: None) # periodically enter python scope
# hook for crash reporter
Exception_Hook.maybe_setup(config=config, slot=self.app.appController.crash)
Exception_Hook.maybe_setup(slot=self.app.appController.crash)
# Initialize any QML plugins
run_hook('init_qml', self.app)

View File

@@ -75,14 +75,13 @@ class QEAppController(BaseCrashReporter, QObject):
secureWindowChanged = pyqtSignal()
wantCloseChanged = pyqtSignal()
def __init__(self, qeapp: 'ElectrumQmlApplication', qedaemon: 'QEDaemon', plugins: 'Plugins'):
def __init__(self, qeapp: 'ElectrumQmlApplication', plugins: 'Plugins'):
BaseCrashReporter.__init__(self, None, None, None)
QObject.__init__(self)
self._app = qeapp
self._qedaemon = qedaemon
self._plugins = plugins
self.config = qedaemon.daemon.config
self.config = QEConfig.instance.config
self._crash_user_text = ''
self._app_started = False
@@ -101,7 +100,7 @@ class QEAppController(BaseCrashReporter, QObject):
self.notification_timer.setInterval(500) # msec
self.notification_timer.timeout.connect(self.on_notification_timer)
self._qedaemon.walletLoaded.connect(self.on_wallet_loaded)
QEDaemon.instance.walletLoaded.connect(self.on_wallet_loaded)
self.userNotify.connect(self.doNotify)
@@ -111,12 +110,12 @@ class QEAppController(BaseCrashReporter, QObject):
self._want_close = False
def on_wallet_loaded(self):
qewallet = self._qedaemon.currentWallet
qewallet = QEDaemon.instance.currentWallet
if not qewallet:
return
# register wallet in Exception_Hook
Exception_Hook.maybe_setup(config=qewallet.wallet.config, wallet=qewallet.wallet)
Exception_Hook.maybe_setup(wallet=qewallet.wallet)
# attach to the wallet user notification events
# connect only once
@@ -344,8 +343,8 @@ class QEAppController(BaseCrashReporter, QObject):
'reportstring': self.get_report_string()
}
@pyqtSlot(object, object, object, object)
def crash(self, config, e, text, tb):
@pyqtSlot(object, object, object)
def crash(self, e, text, tb):
self.exc_args = (e, text, tb) # for BaseCrashReporter
self.showException.emit(self.crashData())
@@ -423,8 +422,6 @@ class ElectrumQmlApplication(QGuiApplication):
self.logger = get_logger(__name__)
ElectrumQmlApplication._daemon = daemon
# TODO QT6 order of declaration is important now?
qmlRegisterType(QEAmount, 'org.electrum', 1, 0, 'Amount')
qmlRegisterType(QENewWalletWizard, 'org.electrum', 1, 0, 'QNewWalletWizard')
@@ -479,17 +476,17 @@ class ElectrumQmlApplication(QGuiApplication):
self.context = self.engine.rootContext()
self.plugins = plugins
self._qeconfig = QEConfig(config)
self._qenetwork = QENetwork(daemon.network, self._qeconfig)
self.config = QEConfig(config)
self.network = QENetwork(daemon.network)
self.daemon = QEDaemon(daemon, self.plugins)
self.appController = QEAppController(self, self.daemon, self.plugins)
self._maxAmount = QEAmount(is_max=True)
self.appController = QEAppController(self, self.plugins)
self.maxAmount = QEAmount(is_max=True)
self.context.setContextProperty('AppController', self.appController)
self.context.setContextProperty('Config', self._qeconfig)
self.context.setContextProperty('Network', self._qenetwork)
self.context.setContextProperty('Config', self.config)
self.context.setContextProperty('Network', self.network)
self.context.setContextProperty('Daemon', self.daemon)
self.context.setContextProperty('FixedFont', self.fixedFont)
self.context.setContextProperty('MAX', self._maxAmount)
self.context.setContextProperty('MAX', self.maxAmount)
self.context.setContextProperty('QRIP', self.qr_ip_h)
self.context.setContextProperty('BUILD', {
'electrum_version': version.ELECTRUM_VERSION,
@@ -527,33 +524,33 @@ class ElectrumQmlApplication(QGuiApplication):
class Exception_Hook(QObject, Logger):
_report_exception = pyqtSignal(object, object, object, object)
_report_exception = pyqtSignal(object, object, object)
_INSTANCE = None # type: Optional[Exception_Hook] # singleton
def __init__(self, *, config: 'SimpleConfig', slot):
def __init__(self, *, slot):
QObject.__init__(self)
Logger.__init__(self)
assert self._INSTANCE is None, "Exception_Hook is supposed to be a singleton"
self.config = config
self.wallet_types_seen = set() # type: Set[str]
sys.excepthook = self.handler
threading.excepthook = self.handler
self._report_exception.connect(slot)
if slot:
self._report_exception.connect(slot)
EarlyExceptionsQueue.set_hook_as_ready()
@classmethod
def maybe_setup(cls, *, config: 'SimpleConfig', wallet: 'Abstract_Wallet' = None, slot = None) -> None:
if not config.SHOW_CRASH_REPORTER:
def maybe_setup(cls, *, wallet: 'Abstract_Wallet' = None, slot=None) -> None:
if not QEConfig.instance.config.SHOW_CRASH_REPORTER:
EarlyExceptionsQueue.set_hook_as_ready() # flush already queued exceptions
return
if not cls._INSTANCE:
cls._INSTANCE = Exception_Hook(config=config, slot=slot)
cls._INSTANCE = Exception_Hook(slot=slot)
if wallet:
cls._INSTANCE.wallet_types_seen.add(wallet.wallet_type)
def handler(self, *exc_info):
self.logger.error('exception caught by crash reporter', exc_info=exc_info)
self._report_exception.emit(self.config, *exc_info)
self._report_exception.emit(*exc_info)

View File

@@ -121,6 +121,8 @@ class QEWalletListModel(QAbstractListModel):
class QEDaemon(AuthMixin, QObject):
instance = None # type: Optional[QEDaemon]
_logger = get_logger(__name__)
_available_wallets = None
@@ -149,6 +151,9 @@ class QEDaemon(AuthMixin, QObject):
def __init__(self, daemon: 'Daemon', plugins: 'Plugins', parent=None):
super().__init__(parent)
if QEDaemon.instance:
raise RuntimeError('There should only be one QEDaemon instance')
QEDaemon.instance = self
self.daemon = daemon
self.plugins = plugins
self.qefx = QEFX(daemon.fx, daemon.config)

View File

@@ -9,10 +9,10 @@ from electrum.interface import ServerAddr
from electrum.fee_policy import FEERATE_DEFAULT_RELAY
from .util import QtEventListener, event_listener
from .qeconfig import QEConfig
from .qeserverlistmodel import QEServerListModel
if TYPE_CHECKING:
from .qeconfig import QEConfig
from electrum.network import Network
@@ -49,18 +49,17 @@ class QENetwork(QObject, QtEventListener):
_gossipDbChannels = 0
_gossipDbPolicies = 0
def __init__(self, network: 'Network', qeconfig: 'QEConfig', parent=None):
def __init__(self, network: 'Network', parent=None):
super().__init__(parent)
assert network, "--offline is not yet implemented for this GUI" # TODO
self.network = network
self._qeconfig = qeconfig
self._serverListModel = None
self._height = network.get_local_height() # init here, update event can take a while
self._server_height = network.get_server_height() # init here, update event can take a while
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
self._qeconfig.useGossipChanged.connect(self.on_gossip_setting_changed)
QEConfig.instance.useGossipChanged.connect(self.on_gossip_setting_changed)
def on_destroy(self):
self.unregister_callbacks()
@@ -172,7 +171,7 @@ class QENetwork(QObject, QtEventListener):
def on_gossip_setting_changed(self):
if not self.network:
return
if self._qeconfig.useGossip:
if QEConfig.instance.useGossip:
self.network.start_gossip()
else:
self.network.run_from_another_thread(self.network.stop_gossip())
@@ -198,7 +197,7 @@ class QENetwork(QObject, QtEventListener):
raise Exception('failed to parse')
except Exception:
return
net_params = net_params._replace(server=server, auto_connect=self._qeconfig.autoConnect)
net_params = net_params._replace(server=server, auto_connect=QEConfig.instance.autoConnect)
self.network.run_from_another_thread(self.network.set_parameters(net_params))
@pyqtProperty(str, notify=statusChanged)

View File

@@ -5,8 +5,9 @@ from electrum.plugin import hook
from electrum.util import UserFacingException
from electrum.gui.qml.qewallet import QEWallet
from .common_qt import TrustedcoinPluginQObject
from electrum.gui.qml.qedaemon import QEDaemon
from .common_qt import TrustedcoinPluginQObject
from .trustedcoin import TrustedCoinPlugin, TrustedCoinException
if TYPE_CHECKING:
@@ -44,7 +45,7 @@ class Plugin(TrustedCoinPlugin):
def init_qml(self, app: 'ElectrumQmlApplication'):
self.logger.debug(f'init_qml hook called, gui={str(type(app))}')
self._app = app
wizard = self._app.daemon.newWalletWizard
wizard = QEDaemon.instance.newWalletWizard
# important: TrustedcoinPluginQObject needs to be parented, as keeping a ref
# in the plugin is not enough to avoid gc
# Note: storing the trustedcoin qt helper in the plugin is different from the desktop client,