6 changed files with 212 additions and 9 deletions
@ -0,0 +1,29 @@
|
||||
import QtQuick 2.6 |
||||
import QtQuick.Controls 2.0 |
||||
import QtQuick.Layouts 1.0 |
||||
import QtQuick.Controls.Material 2.0 |
||||
|
||||
import org.electrum 1.0 |
||||
|
||||
ItemDelegate { |
||||
id: root |
||||
height: itemLayout.height |
||||
width: ListView.view.width |
||||
|
||||
GridLayout { |
||||
id: itemLayout |
||||
anchors { |
||||
left: parent.left |
||||
right: parent.right |
||||
leftMargin: constants.paddingSmall |
||||
rightMargin: constants.paddingSmall |
||||
} |
||||
columns: 2 |
||||
Label { |
||||
text: model.address |
||||
} |
||||
Label { |
||||
text: model.chain |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,133 @@
|
||||
from abc import abstractmethod |
||||
|
||||
from PyQt5.QtCore import pyqtProperty, pyqtSignal, pyqtSlot, QObject |
||||
from PyQt5.QtCore import Qt, QAbstractListModel, QModelIndex |
||||
|
||||
from electrum.i18n import _ |
||||
from electrum.logging import get_logger |
||||
from electrum.util import Satoshis, format_time |
||||
from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL |
||||
from electrum import blockchain |
||||
|
||||
from .util import QtEventListener, qt_event_listener, event_listener |
||||
|
||||
class QEServerListModel(QAbstractListModel, QtEventListener): |
||||
_logger = get_logger(__name__) |
||||
_chaintips = 0 |
||||
|
||||
# define listmodel rolemap |
||||
_ROLE_NAMES=('name', 'address', 'is_connected', 'is_primary', 'is_tor', 'chain', 'height') |
||||
_ROLE_KEYS = range(Qt.UserRole, Qt.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.network = network |
||||
self.init_model() |
||||
self.register_callbacks() |
||||
self.destroyed.connect(lambda: self.unregister_callbacks()) |
||||
|
||||
@event_listener |
||||
def on_event_network_updated(self): |
||||
self._logger.info(f'network updated') |
||||
self.init_model() |
||||
|
||||
@event_listener |
||||
def on_event_blockchain_updated(self): |
||||
self._logger.info(f'blockchain updated') |
||||
self.init_model() |
||||
|
||||
@event_listener |
||||
def on_event_default_server_changed(self): |
||||
self._logger.info(f'default server changed') |
||||
self.init_model() |
||||
|
||||
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.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 init_model(self): |
||||
self.clear() |
||||
|
||||
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 = {} |
||||
server['chain'] = name |
||||
server['chain_height'] = b.height() |
||||
server['is_primary'] = i == self.network.interface |
||||
server['is_connected'] = True |
||||
server['name'] = str(i.server) |
||||
server['address'] = i.server.to_friendly_name() |
||||
server['height'] = i.tip |
||||
|
||||
self._logger.debug(f'adding server: {repr(server)}') |
||||
self.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 |
||||
use_tor = True |
||||
for _host, d in sorted(all_servers.items()): |
||||
if _host in connected_hosts: |
||||
continue |
||||
if _host.endswith('.onion') and not use_tor: |
||||
continue |
||||
port = d.get(protocol) |
||||
if port: |
||||
s = ServerAddr(_host, port, protocol=protocol) |
||||
server = {} |
||||
server['chain'] = '' |
||||
server['chain_height'] = 0 |
||||
server['height'] = 0 |
||||
server['is_primary'] = False |
||||
server['is_connected'] = False |
||||
server['name'] = s.net_addr_str() |
||||
server['address'] = server['name'] |
||||
|
||||
self.servers.append(server) |
||||
|
||||
Loading…
Reference in new issue