You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
139 lines
4.4 KiB
139 lines
4.4 KiB
from PyQt6.QtCore import pyqtProperty, pyqtSignal, pyqtSlot |
|
from PyQt6.QtCore import Qt, QAbstractListModel, QModelIndex |
|
|
|
from electrum.logging import get_logger |
|
from electrum.util import Satoshis |
|
from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL |
|
from electrum import blockchain |
|
|
|
from .util import QtEventListener, qt_event_listener |
|
|
|
|
|
class QEServerListModel(QAbstractListModel, QtEventListener): |
|
_logger = get_logger(__name__) |
|
|
|
# define listmodel rolemap |
|
_ROLE_NAMES=('name', 'address', 'is_connected', 'is_primary', 'is_tor', 'chain', 'height') |
|
_ROLE_KEYS = range(Qt.ItemDataRole.UserRole, Qt.ItemDataRole.UserRole + len(_ROLE_NAMES)) |
|
_ROLE_MAP = dict(zip(_ROLE_KEYS, [bytearray(x.encode()) for x in _ROLE_NAMES])) |
|
_ROLE_RMAP = dict(zip(_ROLE_NAMES, _ROLE_KEYS)) |
|
|
|
def __init__(self, network, parent=None): |
|
super().__init__(parent) |
|
|
|
self._chaintips = 0 |
|
self._servers = [] |
|
|
|
self.network = network |
|
self.initModel() |
|
self.register_callbacks() |
|
self.destroyed.connect(lambda: self.unregister_callbacks()) |
|
|
|
@qt_event_listener |
|
def on_event_network_updated(self): |
|
self._logger.info(f'network updated') |
|
self.initModel() |
|
|
|
@qt_event_listener |
|
def on_event_blockchain_updated(self): |
|
self._logger.info(f'blockchain updated') |
|
self.initModel() |
|
|
|
@qt_event_listener |
|
def on_event_default_server_changed(self): |
|
self._logger.info(f'default server changed') |
|
self.initModel() |
|
|
|
def rowCount(self, index): |
|
return len(self._servers) |
|
|
|
def roleNames(self): |
|
return self._ROLE_MAP |
|
|
|
def data(self, index, role): |
|
server = self._servers[index.row()] |
|
role_index = role - Qt.ItemDataRole.UserRole |
|
value = server[self._ROLE_NAMES[role_index]] |
|
|
|
if isinstance(value, (bool, list, int, str)) or value is None: |
|
return value |
|
if isinstance(value, Satoshis): |
|
return value.value |
|
return str(value) |
|
|
|
def clear(self): |
|
self.beginResetModel() |
|
self._servers = [] |
|
self.endResetModel() |
|
|
|
chaintipsChanged = pyqtSignal() |
|
@pyqtProperty(int, notify=chaintipsChanged) |
|
def chaintips(self): |
|
return self._chaintips |
|
|
|
def get_chains(self): |
|
chains = self.network.get_blockchains() |
|
n_chains = len(chains) |
|
if n_chains != self._chaintips: |
|
self._chaintips = n_chains |
|
self.chaintipsChanged.emit() |
|
return chains |
|
|
|
@pyqtSlot() |
|
def initModel(self): |
|
self.clear() |
|
|
|
servers = [] |
|
|
|
chains = self.get_chains() |
|
|
|
for chain_id, interfaces in chains.items(): |
|
self._logger.debug(f'chain {chain_id} has {len(interfaces)} interfaces') |
|
b = blockchain.blockchains.get(chain_id) |
|
if b is None: |
|
continue |
|
|
|
name = b.get_name() |
|
|
|
self._logger.debug(f'chain {chain_id} has name={name}, max_forkpoint=@{b.get_max_forkpoint()}, height={b.height()}') |
|
|
|
for i in interfaces: |
|
server = { |
|
'chain': name, |
|
'chain_height': b.height(), |
|
'is_primary': i == self.network.interface, |
|
'is_connected': True, |
|
'name': str(i.server), |
|
'address': i.server.to_friendly_name(), |
|
'height': i.tip |
|
} |
|
|
|
servers.append(server) |
|
|
|
# disconnected servers |
|
all_servers = self.network.get_servers() |
|
connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces]) |
|
protocol = PREFERRED_NETWORK_PROTOCOL |
|
for _host, d in sorted(all_servers.items()): |
|
if _host in connected_hosts: |
|
continue |
|
if _host.endswith('.onion') and not self.network.is_proxy_tor: |
|
continue |
|
port = d.get(protocol) |
|
if port: |
|
s = ServerAddr(_host, port, protocol=protocol) |
|
server = { |
|
'chain': '', |
|
'chain_height': 0, |
|
'height': 0, |
|
'is_primary': False, |
|
'is_connected': False, |
|
'name': s.net_addr_str() |
|
} |
|
server['address'] = server['name'] |
|
|
|
servers.append(server) |
|
|
|
self.beginInsertRows(QModelIndex(), 0, len(servers) - 1) |
|
self._servers = servers |
|
self.endInsertRows()
|
|
|