1
0

Merge pull request #10378 from SomberNight/202512_network_gui_disconnected_servers

network gui: always show bookmarked servers in list
This commit is contained in:
ghost43
2025-12-19 12:26:09 +00:00
committed by GitHub
4 changed files with 45 additions and 44 deletions

View File

@@ -111,28 +111,18 @@ class QEServerListModel(QAbstractListModel, QtEventListener):
servers.append(server) servers.append(server)
# disconnected servers # disconnected servers
all_servers = self.network.get_servers() for s in self.network.get_disconnected_server_addrs():
connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces]) server = {
protocol = PREFERRED_NETWORK_PROTOCOL 'chain': '',
for _host, d in sorted(all_servers.items()): 'chain_height': 0,
if _host in connected_hosts: 'height': 0,
continue 'is_primary': False,
if _host.endswith('.onion') and not self.network.is_proxy_tor: 'is_connected': False,
continue 'name': s.to_friendly_name()
port = d.get(protocol) }
if port: server['address'] = server['name']
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) servers.append(server)
self.beginInsertRows(QModelIndex(), 0, len(servers) - 1) self.beginInsertRows(QModelIndex(), 0, len(servers) - 1)
self._servers = servers self._servers = servers

View File

@@ -149,9 +149,6 @@ class NodesListWidget(QTreeWidget):
def update(self): def update(self):
self.clear() self.clear()
network = self.network network = self.network
servers = self.network.get_servers()
use_tor = bool(network.is_proxy_tor)
# connected servers # connected servers
connected_servers_item = QTreeWidgetItem([_("Connected nodes"), '']) connected_servers_item = QTreeWidgetItem([_("Connected nodes"), ''])
@@ -185,19 +182,8 @@ class NodesListWidget(QTreeWidget):
# disconnected servers # disconnected servers
disconnected_servers_item = QTreeWidgetItem([_("Other known servers"), ""]) disconnected_servers_item = QTreeWidgetItem([_("Other known servers"), ""])
disconnected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL) disconnected_servers_item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.TOPLEVEL)
connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces]) for server in network.get_disconnected_server_addrs():
protocol = PREFERRED_NETWORK_PROTOCOL item = QTreeWidgetItem([server.to_friendly_name(), ""])
server_addrs = [
ServerAddr(_host, port, protocol=protocol)
for _host, d in servers.items()
if (port := d.get(protocol))]
server_addrs.sort(key=lambda x: (-network.is_server_bookmarked(x), str(x)))
for server in server_addrs:
if server.host in connected_hosts:
continue
if server.host.endswith('.onion') and not use_tor:
continue
item = QTreeWidgetItem([server.net_addr_str(), ""])
item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER)
item.setData(0, self.SERVER_ADDR_ROLE, server) item.setData(0, self.SERVER_ADDR_ROLE, server)
if network.is_server_bookmarked(server): if network.is_server_bookmarked(server):

View File

@@ -75,9 +75,9 @@ ca_path = certifi.where()
BUCKET_NAME_OF_ONION_SERVERS = 'onion' BUCKET_NAME_OF_ONION_SERVERS = 'onion'
_KNOWN_NETWORK_PROTOCOLS = {'t', 's'} KNOWN_ELEC_PROTOCOL_TRANSPORTS = {'t', 's'}
PREFERRED_NETWORK_PROTOCOL = 's' PREFERRED_NETWORK_PROTOCOL = 's'
assert PREFERRED_NETWORK_PROTOCOL in _KNOWN_NETWORK_PROTOCOLS assert PREFERRED_NETWORK_PROTOCOL in KNOWN_ELEC_PROTOCOL_TRANSPORTS
MAX_NUM_HEADERS_PER_REQUEST = 2016 MAX_NUM_HEADERS_PER_REQUEST = 2016
assert MAX_NUM_HEADERS_PER_REQUEST >= CHUNK_SIZE assert MAX_NUM_HEADERS_PER_REQUEST >= CHUNK_SIZE
@@ -462,7 +462,7 @@ class ServerAddr:
net_addr = NetAddress(host, port) # this validates host and port net_addr = NetAddress(host, port) # this validates host and port
except Exception as e: except Exception as e:
raise ValueError(f"cannot construct ServerAddr: invalid host or port (host={host}, port={port})") from e raise ValueError(f"cannot construct ServerAddr: invalid host or port (host={host}, port={port})") from e
if protocol not in _KNOWN_NETWORK_PROTOCOLS: if protocol not in KNOWN_ELEC_PROTOCOL_TRANSPORTS:
raise ValueError(f"invalid network protocol: {protocol}") raise ValueError(f"invalid network protocol: {protocol}")
self.host = str(net_addr.host) # canonical form (if e.g. IPv6 address) self.host = str(net_addr.host) # canonical form (if e.g. IPv6 address)
self.port = int(net_addr.port) self.port = int(net_addr.port)

View File

@@ -30,7 +30,7 @@ import threading
import json import json
from typing import ( from typing import (
NamedTuple, Optional, Sequence, List, Dict, Tuple, TYPE_CHECKING, Iterable, Set, Any, TypeVar, NamedTuple, Optional, Sequence, List, Dict, Tuple, TYPE_CHECKING, Iterable, Set, Any, TypeVar,
Callable Callable, Mapping,
) )
import copy import copy
import functools import functools
@@ -53,7 +53,7 @@ from .transaction import Transaction
from .blockchain import Blockchain from .blockchain import Blockchain
from .interface import ( from .interface import (
Interface, PREFERRED_NETWORK_PROTOCOL, RequestTimedOut, NetworkTimeout, BUCKET_NAME_OF_ONION_SERVERS, Interface, PREFERRED_NETWORK_PROTOCOL, RequestTimedOut, NetworkTimeout, BUCKET_NAME_OF_ONION_SERVERS,
NetworkException, RequestCorrupted, ServerAddr, TxBroadcastError, NetworkException, RequestCorrupted, ServerAddr, TxBroadcastError, KNOWN_ELEC_PROTOCOL_TRANSPORTS,
) )
from .version import PROTOCOL_VERSION_MIN from .version import PROTOCOL_VERSION_MIN
from .i18n import _ from .i18n import _
@@ -624,7 +624,7 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
@with_recent_servers_lock @with_recent_servers_lock
def get_servers(self): def get_servers(self) -> Mapping[str, Mapping[str, str]]:
# note: order of sources when adding servers here is crucial! # note: order of sources when adding servers here is crucial!
# don't let "server_peers" overwrite anything, # don't let "server_peers" overwrite anything,
# otherwise main server can eclipse the client # otherwise main server can eclipse the client
@@ -659,6 +659,31 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
out = filter_noonion(out) out = filter_noonion(out)
return out return out
def get_disconnected_server_addrs(self) -> Sequence[ServerAddr]:
hostmap = self.get_servers()
disconnected_server_addrs = [] # type: List[ServerAddr]
chains = self.get_blockchains()
connected_hosts = set([iface.host for ifaces in chains.values() for iface in ifaces])
# convert hostmap to list of ServerAddrs (one-to-many mapping)
server_addrs = []
for host, portmap in hostmap.items():
for protocol in KNOWN_ELEC_PROTOCOL_TRANSPORTS:
if port := portmap.get(protocol):
server_addrs.append(ServerAddr(host, port, protocol=protocol))
# sort bookmarked servers to appear first
server_addrs.sort(key=lambda x: (-self.is_server_bookmarked(x), str(x)))
# filter out stuff
for server in server_addrs:
if server.host in connected_hosts:
continue
if not self.is_server_bookmarked(server):
if server.protocol != PREFERRED_NETWORK_PROTOCOL:
continue
if server.host.endswith('.onion') and not self.is_proxy_tor:
continue
disconnected_server_addrs.append(server)
return disconnected_server_addrs
def _get_next_server_to_try(self) -> Optional[ServerAddr]: def _get_next_server_to_try(self) -> Optional[ServerAddr]:
now = time.time() now = time.time()
with self.interfaces_lock: with self.interfaces_lock:
@@ -1122,7 +1147,7 @@ class Network(Logger, NetworkRetryManager[ServerAddr]):
self._blockchain = interface.blockchain self._blockchain = interface.blockchain
return self._blockchain return self._blockchain
def get_blockchains(self): def get_blockchains(self) -> Mapping[str, Sequence[Interface]]:
out = {} # blockchain_id -> list(interfaces) out = {} # blockchain_id -> list(interfaces)
with blockchain.blockchains_lock: blockchain_items = list(blockchain.blockchains.items()) with blockchain.blockchains_lock: blockchain_items = list(blockchain.blockchains.items())
with self.interfaces_lock: interfaces_values = list(self.interfaces.values()) with self.interfaces_lock: interfaces_values = list(self.interfaces.values())