Browse Source

refactor to new event listener framework

patch-4
Sander van Grieken 3 years ago
parent
commit
0228169852
  1. 17
      electrum/gui/qml/qechanneldetails.py
  2. 41
      electrum/gui/qml/qechannellistmodel.py
  3. 4
      electrum/gui/qml/qedaemon.py
  4. 18
      electrum/gui/qml/qefx.py
  5. 4
      electrum/gui/qml/qeinvoice.py
  6. 30
      electrum/gui/qml/qenetwork.py
  7. 143
      electrum/gui/qml/qewallet.py
  8. 31
      electrum/gui/qml/util.py

17
electrum/gui/qml/qechanneldetails.py

@ -5,14 +5,14 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS
from electrum.i18n import _
from electrum.gui import messages
from electrum.logging import get_logger
from electrum.util import register_callback, unregister_callback
from electrum.lnutil import LOCAL, REMOTE
from electrum.lnchannel import ChanCloseOption
from .qewallet import QEWallet
from .qetypes import QEAmount
from .util import QtEventListener, qt_event_listener
class QEChannelDetails(QObject):
class QEChannelDetails(QObject, QtEventListener):
_logger = get_logger(__name__)
_wallet = None
@ -25,17 +25,16 @@ class QEChannelDetails(QObject):
def __init__(self, parent=None):
super().__init__(parent)
register_callback(self.on_network, ['channel'])
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
def on_network(self, event, *args):
if event == 'channel':
wallet, channel = args
if wallet == self._wallet.wallet and self._channelid == channel.channel_id.hex():
self.channelChanged.emit()
@qt_event_listener
def on_event_channel(self, wallet, channel):
if wallet == self._wallet.wallet and self._channelid == channel.channel_id.hex():
self.channelChanged.emit()
def on_destroy(self):
unregister_callback(self.on_network)
self.unregister_callbacks()
walletChanged = pyqtSignal()
@pyqtProperty(QEWallet, notify=walletChanged)

41
electrum/gui/qml/qechannellistmodel.py

@ -4,13 +4,14 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.logging import get_logger
from electrum.util import Satoshis, register_callback, unregister_callback
from electrum.util import Satoshis
from electrum.lnutil import LOCAL, REMOTE
from electrum.lnchannel import ChannelState
from .qetypes import QEAmount
from .util import QtEventListener, qt_event_listener
class QEChannelListModel(QAbstractListModel):
class QEChannelListModel(QAbstractListModel, QtEventListener):
_logger = get_logger(__name__)
# define listmodel rolemap
@ -28,38 +29,26 @@ class QEChannelListModel(QAbstractListModel):
self.wallet = wallet
self.init_model()
self._network_signal.connect(self.on_network_qt)
interests = ['channel', 'channels_updated', 'gossip_peers',
'ln_gossip_sync_progress', 'unknown_channels',
'channel_db', 'gossip_db_loaded']
# To avoid leaking references to "self" that prevent the
# window from being GC-ed when closed, callbacks should be
# methods of this class only, and specifically not be
# partials, lambdas or methods of subobjects. Hence...
register_callback(self.on_network, interests)
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
def on_network(self, event, *args):
if event in ['channel','channels_updated']:
# Handle in GUI thread (_network_signal -> on_network_qt)
self._network_signal.emit(event, args)
else:
self.on_network_qt(event, args)
def on_network_qt(self, event, args=None):
if event == 'channel':
wallet, channel = args
if wallet == self.wallet:
self.on_channel_updated(channel)
elif event == 'channels_updated':
wallet, = args
if wallet == self.wallet:
self.init_model() # TODO: remove/add less crude than full re-init
else:
self._logger.debug('unhandled event %s: %s' % (event, repr(args)))
@qt_event_listener
def on_event_channel(self, wallet, channel):
if wallet == self.wallet:
self.on_channel_updated(channel)
# elif event == 'channels_updated':
@qt_event_listener
def on_event_channels_updated(self, wallet):
if wallet == self.wallet:
self.init_model() # TODO: remove/add less crude than full re-init
def on_destroy(self):
unregister_callback(self.on_network)
self.unregister_callbacks()
def rowCount(self, index):
return len(self.channels)

4
electrum/gui/qml/qedaemon.py

@ -6,7 +6,7 @@ from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex
from electrum.util import register_callback, get_new_wallet_name, WalletFileException
from electrum.logging import get_logger
from electrum.wallet import Wallet, Abstract_Wallet, update_password_for_directory
from electrum.wallet import Wallet, Abstract_Wallet
from electrum.storage import WalletStorage, StorageReadWriteError
from electrum.wallet_db import WalletDB
@ -147,7 +147,7 @@ class QEDaemon(AuthMixin, QObject):
self.walletLoaded.emit()
if self.daemon.config.get('single_password'):
self._use_single_password = update_password_for_directory(self.daemon.config, password, password)
self._use_single_password = self.daemon.update_password_for_directory(old_password=password, new_password=password)
self._password = password
self._logger.info(f'use single password: {self._use_single_password}')

18
electrum/gui/qml/qefx.py

@ -6,28 +6,34 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.logging import get_logger
from electrum.exchange_rate import FxThread
from electrum.simple_config import SimpleConfig
from electrum.util import register_callback
from electrum.bitcoin import COIN
from .qetypes import QEAmount
from .util import QtEventListener, qt_event_listener
class QEFX(QObject):
class QEFX(QObject, QtEventListener):
def __init__(self, fxthread: FxThread, config: SimpleConfig, parent=None):
super().__init__(parent)
self.fx = fxthread
self.config = config
register_callback(self.on_quotes, ['on_quotes'])
register_callback(self.on_history, ['on_history'])
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
_logger = get_logger(__name__)
quotesUpdated = pyqtSignal()
def on_quotes(self, event, *args):
def on_destroy(self):
self.unregister_callbacks()
@qt_event_listener
def on_event_on_quotes(self, *args):
self._logger.debug('new quotes')
self.quotesUpdated.emit()
historyUpdated = pyqtSignal()
def on_history(self, event, *args):
@qt_event_listener
def on_event_on_history(self, *args):
self._logger.debug('new history')
self.historyUpdated.emit()

4
electrum/gui/qml/qeinvoice.py

@ -6,7 +6,7 @@ from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, Q_ENUMS
from electrum.logging import get_logger
from electrum.i18n import _
from electrum.util import (parse_URI, create_bip21_uri, InvalidBitcoinURI, InvoiceError,
maybe_extract_bolt11_invoice)
maybe_extract_lightning_payment_identifier)
from electrum.invoices import Invoice
from electrum.invoices import (PR_UNPAID,PR_EXPIRED,PR_UNKNOWN,PR_PAID,PR_INFLIGHT,
PR_FAILED,PR_ROUTING,PR_UNCONFIRMED,LN_EXPIRY_NEVER)
@ -335,7 +335,7 @@ class QEInvoiceParser(QEInvoice):
lninvoice = None
try:
maybe_lightning_invoice = maybe_extract_bolt11_invoice(maybe_lightning_invoice)
maybe_lightning_invoice = maybe_extract_lightning_payment_identifier(maybe_lightning_invoice)
lninvoice = Invoice.from_bech32(maybe_lightning_invoice)
except InvoiceError as e:
pass

30
electrum/gui/qml/qenetwork.py

@ -1,20 +1,16 @@
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.util import register_callback
from electrum.logging import get_logger
from electrum import constants
from electrum.interface import ServerAddr
class QENetwork(QObject):
from .util import QtEventListener, qt_event_listener
class QENetwork(QObject, QtEventListener):
def __init__(self, network, parent=None):
super().__init__(parent)
self.network = network
register_callback(self.on_network_updated, ['network_updated'])
register_callback(self.on_blockchain_updated, ['blockchain_updated'])
register_callback(self.on_default_server_changed, ['default_server_changed'])
register_callback(self.on_proxy_set, ['proxy_set'])
register_callback(self.on_status, ['status'])
register_callback(self.on_fee_histogram, ['fee_histogram'])
self.register_callbacks()
_logger = get_logger(__name__)
@ -33,30 +29,36 @@ class QENetwork(QObject):
_height = 0
_status = ""
def on_network_updated(self, event, *args):
@qt_event_listener
def on_event_network_updated(self, *args):
self.networkUpdated.emit()
def on_blockchain_updated(self, event, *args):
@qt_event_listener
def on_event_blockchain_updated(self, *args):
if self._height != self.network.get_local_height():
self._height = self.network.get_local_height()
self._logger.debug('new height: %d' % self._height)
self.heightChanged.emit(self._height)
self.blockchainUpdated.emit()
def on_default_server_changed(self, event, *args):
@qt_event_listener
def on_event_default_server_changed(self, *args):
self.defaultServerChanged.emit()
def on_proxy_set(self, event, *args):
@qt_event_listener
def on_event_proxy_set(self, *args):
self._logger.debug('proxy set')
self.proxySet.emit()
def on_status(self, event, *args):
@qt_event_listener
def on_event_status(self, *args):
self._logger.debug('status updated: %s' % self.network.connection_status)
if self._status != self.network.connection_status:
self._status = self.network.connection_status
self.statusChanged.emit()
def on_fee_histogram(self, event, *args):
@qt_event_listener
def on_event_fee_histogram(self, *args):
self._logger.debug('fee histogram updated')
self.feeHistogramUpdated.emit()

143
electrum/gui/qml/qewallet.py

@ -7,8 +7,8 @@ import threading
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject, QUrl, QTimer
from electrum.i18n import _
from electrum.util import (register_callback, unregister_callback,
Satoshis, format_time, parse_max_spend, InvalidPassword)
from electrum.util import (Satoshis, format_time, parse_max_spend, InvalidPassword,
event_listener)
from electrum.logging import get_logger
from electrum.wallet import Wallet, Abstract_Wallet
from electrum.storage import StorageEncryptionVersion
@ -24,8 +24,9 @@ from .qeaddresslistmodel import QEAddressListModel
from .qechannellistmodel import QEChannelListModel
from .qetypes import QEAmount
from .auth import AuthMixin, auth_protect
from .util import QtEventListener, qt_event_listener
class QEWallet(AuthMixin, QObject):
class QEWallet(AuthMixin, QObject, QtEventListener):
__instances = []
# this factory method should be used to instantiate QEWallet
@ -79,7 +80,7 @@ class QEWallet(AuthMixin, QObject):
self.notification_timer.setInterval(500) # msec
self.notification_timer.timeout.connect(self.notify_transactions)
self._network_signal.connect(self.on_network_qt)
#self._network_signal.connect(self.on_network_qt)
interests = ['wallet_updated', 'new_transaction', 'status', 'verified',
'on_history', 'channel', 'channels_updated', 'payment_failed',
'payment_succeeded', 'invoice_status', 'request_status']
@ -87,7 +88,8 @@ class QEWallet(AuthMixin, QObject):
# window from being GC-ed when closed, callbacks should be
# methods of this class only, and specifically not be
# partials, lambdas or methods of subobjects. Hence...
register_callback(self.on_network, interests)
#register_callback(self.on_network, interests)
self.register_callbacks()
self.destroyed.connect(lambda: self.on_destroy())
@pyqtProperty(bool, notify=isUptodateChanged)
@ -108,60 +110,93 @@ class QEWallet(AuthMixin, QObject):
wallet = args[0]
if wallet == self.wallet:
self._logger.debug('event %s' % event)
if event == 'status':
@event_listener
def on_event_status(self, *args, **kwargs):
#if event == 'status':
self.isUptodateChanged.emit()
elif event == 'request_status':
wallet, key, status = args
if wallet == self.wallet:
self._logger.debug('request status %d for key %s' % (status, key))
self.requestStatusChanged.emit(key, status)
elif event == 'invoice_status':
wallet, key = args
if wallet == self.wallet:
self._logger.debug('invoice status update for key %s' % key)
# FIXME event doesn't pass the new status, so we need to retrieve
invoice = self.wallet.get_invoice(key)
if invoice:
status = self.wallet.get_invoice_status(invoice)
self.invoiceStatusChanged.emit(key, status)
else:
self._logger.debug(f'No invoice found for key {key}')
elif event == 'new_transaction':
wallet, tx = args
if wallet == self.wallet:
self.add_tx_notification(tx)
self.historyModel.init_model() # TODO: be less dramatic
elif event == 'verified':
wallet, txid, info = args
if wallet == self.wallet:
self.historyModel.update_tx(txid, info)
elif event == 'wallet_updated':
wallet, = args
if wallet == self.wallet:
self._logger.debug('wallet %s updated' % str(wallet))
self.balanceChanged.emit()
elif event == 'channel':
wallet, channel = args
if wallet == self.wallet:
self.balanceChanged.emit()
elif event == 'channels_updated':
wallet, = args
# elif event == 'request_status':
@event_listener
def on_event_request_status(self, wallet, key, status):
#wallet, key, status = args
if wallet == self.wallet:
self._logger.debug('request status %d for key %s' % (status, key))
self.requestStatusChanged.emit(key, status)
# elif event == 'invoice_status':
@event_listener
def on_event_invoice_status(self, wallet, key):
#wallet, key = args
if wallet == self.wallet:
self._logger.debug('invoice status update for key %s' % key)
# FIXME event doesn't pass the new status, so we need to retrieve
invoice = self.wallet.get_invoice(key)
if invoice:
status = self.wallet.get_invoice_status(invoice)
self.invoiceStatusChanged.emit(key, status)
else:
self._logger.debug(f'No invoice found for key {key}')
#elif event == 'new_transaction':
@qt_event_listener
def on_event_new_transaction(self, *args):
wallet, tx = args
if wallet == self.wallet:
self.add_tx_notification(tx)
self.historyModel.init_model() # TODO: be less dramatic
# elif event == 'verified':
@qt_event_listener
def on_event_verified(self, wallet, txid, info):
#wallet, txid, info = args
if wallet == self.wallet:
self.historyModel.update_tx(txid, info)
# elif event == 'wallet_updated':
@event_listener
def on_event_wallet_updated(self, wallet):
#wallet, = args
if wallet == self.wallet:
self._logger.debug('wallet %s updated' % str(wallet))
self.balanceChanged.emit()
# elif event == 'channel':
@event_listener
def on_event_channel(self, wallet, channel):
#wallet, channel = args
if wallet == self.wallet:
self.balanceChanged.emit()
elif event == 'payment_succeeded':
wallet, key = args
if wallet == self.wallet:
self.paymentSucceeded.emit(key)
self.historyModel.init_model() # TODO: be less dramatic
elif event == 'payment_failed':
wallet, key, reason = args
if wallet == self.wallet:
self.paymentFailed.emit(key, reason)
else:
self._logger.debug('unhandled event: %s %s' % (event, str(args)))
# elif event == 'channels_updated':
@event_listener
def on_event_channels_updated(self, wallet):
#wallet, = args
if wallet == self.wallet:
self.balanceChanged.emit()
# elif event == 'payment_succeeded':
@qt_event_listener
def on_event_payment_succeeded(self, wallet, key):
#wallet, key = args
if wallet == self.wallet:
self.paymentSucceeded.emit(key)
self.historyModel.init_model() # TODO: be less dramatic
# elif event == 'payment_failed':
@event_listener
def on_event_payment_failed(self, wallet, key, reason):
#wallet, key, reason = args
if wallet == self.wallet:
self.paymentFailed.emit(key, reason)
#else:
#self._logger.debug('unhandled event: %s %s' % (event, str(args)))
def on_destroy(self):
unregister_callback(self.on_network)
#unregister_callback(self.on_network)
self.unregister_callbacks()
def add_tx_notification(self, tx):
self._logger.debug('new transaction event')

31
electrum/gui/qml/util.py

@ -0,0 +1,31 @@
from functools import wraps
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject
from electrum.logging import get_logger
from electrum.i18n import _
from electrum.util import EventListener, event_listener
class QtEventListener(EventListener):
qt_callback_signal = pyqtSignal(tuple)
def register_callbacks(self):
self.qt_callback_signal.connect(self.on_qt_callback_signal)
EventListener.register_callbacks(self)
def unregister_callbacks(self):
#self.qt_callback_signal.disconnect()
EventListener.unregister_callbacks(self)
def on_qt_callback_signal(self, args):
func = args[0]
return func(self, *args[1:])
# decorator for members of the QtEventListener class
def qt_event_listener(func):
func = event_listener(func)
@wraps(func)
def decorator(self, *args):
self.qt_callback_signal.emit( (func,) + args)
return decorator
Loading…
Cancel
Save