tnetwork/gui: unify host/port input fields to single server str - electrum - Electrum Bitcoin wallet
 (HTM) git clone https://git.parazyd.org/electrum
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
       ---
 (DIR) commit 9e57ae630ba96e6d2c40288d2633aeca8d20764d
 (DIR) parent b2cfaddff25b93189e8fb26f04fe9667958fe2d6
 (HTM) Author: SomberNight <somber.night@protonmail.com>
       Date:   Thu, 16 Apr 2020 21:12:23 +0200
       
       network/gui: unify host/port input fields to single server str
       
       This allows optionally specifying the protocol for the main server.
       
       fixes #6095
       fixes #5278
       
       Diffstat:
         M electrum/gui/kivy/main_window.py    |       6 ++----
         M electrum/gui/kivy/uix/ui_screens/s… |      23 ++++-------------------
         M electrum/gui/qt/network_dialog.py   |      51 ++++++++-----------------------
         M electrum/interface.py               |      24 +++++++++++++++++++++++-
         M electrum/network.py                 |       6 +-----
       
       5 files changed, 42 insertions(+), 68 deletions(-)
       ---
 (DIR) diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py
       t@@ -145,13 +145,11 @@ class ElectrumWindow(App):
                servers = self.network.get_servers()
                ChoiceDialog(_('Choose a server'), sorted(servers), popup.ids.host.text, cb2).open()
        
       -    def maybe_switch_to_server(self, *, host: str, port: str):
       +    def maybe_switch_to_server(self, server_str: str):
                from electrum.interface import ServerAddr
                net_params = self.network.get_parameters()
                try:
       -            server = ServerAddr(host=host,
       -                                port=port,
       -                                protocol=net_params.server.protocol)
       +            server = ServerAddr.from_str_with_inference(server_str)
                except Exception as e:
                    self.show_error(_("Invalid server details: {}").format(repr(e)))
                    return
 (DIR) diff --git a/electrum/gui/kivy/uix/ui_screens/server.kv b/electrum/gui/kivy/uix/ui_screens/server.kv
       t@@ -1,5 +1,3 @@
       -#:import ServerAddr electrum.interface.ServerAddr
       -
        Popup:
            id: nd
            title: _('Server')
       t@@ -18,27 +16,14 @@ Popup:
                        height: '36dp'
                        size_hint_x: 1
                        size_hint_y: None
       -                text: _('Host') + ':'
       +                text: _('Server') + ':'
                    TextInput:
       -                id: host
       +                id: server_str
                        multiline: False
                        height: '36dp'
                        size_hint_x: 3
                        size_hint_y: None
       -                text: app.network.get_parameters().server.host
       -            Label:
       -                height: '36dp'
       -                size_hint_x: 1
       -                size_hint_y: None
       -                text: _('Port') + ':'
       -            TextInput:
       -                id: port
       -                multiline: False
       -                input_type: 'number'
       -                height: '36dp'
       -                size_hint_x: 3
       -                size_hint_y: None
       -                text: str(app.network.get_parameters().server.port)
       +                text: app.network.get_parameters().server.net_addr_str()
                    Widget
                    Button:
                        id: chooser
       t@@ -58,5 +43,5 @@ Popup:
                        height: '48dp'
                        text: _('OK')
                        on_release:
       -                    app.maybe_switch_to_server(host=str(root.ids.host.text), port=str(root.ids.port.text))
       +                    app.maybe_switch_to_server(str(root.ids.server_str.text))
                            nd.dismiss()
 (DIR) diff --git a/electrum/gui/qt/network_dialog.py b/electrum/gui/qt/network_dialog.py
       t@@ -36,8 +36,8 @@ from PyQt5.QtGui import QFontMetrics
        
        from electrum.i18n import _
        from electrum import constants, blockchain, util
       -from electrum.interface import ServerAddr
       -from electrum.network import Network, PREFERRED_NETWORK_PROTOCOL
       +from electrum.interface import ServerAddr, PREFERRED_NETWORK_PROTOCOL
       +from electrum.network import Network
        from electrum.logging import get_logger
        
        from .util import (Buttons, CloseButton, HelpButton, read_QIcon, char_width_in_lineedit,
       t@@ -171,8 +171,7 @@ class ServerListWidget(QTreeWidget):
                menu.exec_(self.viewport().mapToGlobal(position))
        
            def set_server(self, server: ServerAddr):
       -        self.parent.server_host.setText(server.host)
       -        self.parent.server_port.setText(str(server.port))
       +        self.parent.server_e.setText(server.net_addr_str())
                self.parent.set_server()
        
            def keyPressEvent(self, event):
       t@@ -230,15 +229,12 @@ class NetworkChoiceLayout(object):
                grid = QGridLayout(server_tab)
                grid.setSpacing(8)
        
       -        self.server_host = QLineEdit()
       -        self.server_host.setFixedWidth(fixed_width_hostname)
       -        self.server_port = QLineEdit()
       -        self.server_port.setFixedWidth(fixed_width_port)
       +        self.server_e = QLineEdit()
       +        self.server_e.setFixedWidth(fixed_width_hostname + fixed_width_port)
                self.autoconnect_cb = QCheckBox(_('Select server automatically'))
                self.autoconnect_cb.setEnabled(self.config.is_modifiable('auto_connect'))
        
       -        self.server_host.editingFinished.connect(self.set_server)
       -        self.server_port.editingFinished.connect(self.set_server)
       +        self.server_e.editingFinished.connect(self.set_server)
                self.autoconnect_cb.clicked.connect(self.set_server)
                self.autoconnect_cb.clicked.connect(self.update)
        
       t@@ -250,8 +246,7 @@ class NetworkChoiceLayout(object):
                grid.addWidget(HelpButton(msg), 0, 4)
        
                grid.addWidget(QLabel(_('Server') + ':'), 1, 0)
       -        grid.addWidget(self.server_host, 1, 1, 1, 2)
       -        grid.addWidget(self.server_port, 1, 3)
       +        grid.addWidget(self.server_e, 1, 1, 1, 3)
        
                label = _('Server peers') if network.is_connected() else _('Default Servers')
                grid.addWidget(QLabel(label), 2, 0, 1, 5)
       t@@ -355,20 +350,18 @@ class NetworkChoiceLayout(object):
            def enable_set_server(self):
                if self.config.is_modifiable('server'):
                    enabled = not self.autoconnect_cb.isChecked()
       -            self.server_host.setEnabled(enabled)
       -            self.server_port.setEnabled(enabled)
       +            self.server_e.setEnabled(enabled)
                    self.servers_list.setEnabled(enabled)
                else:
       -            for w in [self.autoconnect_cb, self.server_host, self.server_port, self.servers_list]:
       +            for w in [self.autoconnect_cb, self.server_e, self.servers_list]:
                        w.setEnabled(False)
        
            def update(self):
                net_params = self.network.get_parameters()
                server = net_params.server
                proxy_config, auto_connect = net_params.proxy, net_params.auto_connect
       -        if not self.server_host.hasFocus() and not self.server_port.hasFocus():
       -            self.server_host.setText(server.host)
       -            self.server_port.setText(str(server.port))
       +        if not self.server_e.hasFocus():
       +            self.server_e.setText(server.net_addr_str())
                self.autoconnect_cb.setChecked(auto_connect)
        
                interface = self.network.interface
       t@@ -425,33 +418,13 @@ class NetworkChoiceLayout(object):
                self.network.run_from_another_thread(self.network.follow_chain_given_server(server))
                self.update()
        
       -    def change_server(self, host, protocol):
       -        pp = self.servers.get(host, constants.net.DEFAULT_PORTS)
       -        if protocol and protocol not in protocol_letters:
       -            protocol = None
       -        if protocol:
       -            port = pp.get(protocol)
       -            if port is None:
       -                protocol = None
       -        if not protocol:
       -            if 's' in pp.keys():
       -                protocol = 's'
       -                port = pp.get(protocol)
       -            else:
       -                protocol = list(pp.keys())[0]
       -                port = pp.get(protocol)
       -        self.server_host.setText(host)
       -        self.server_port.setText(port)
       -
            def accept(self):
                pass
        
            def set_server(self):
                net_params = self.network.get_parameters()
                try:
       -            server = ServerAddr(host=str(self.server_host.text()),
       -                                port=str(self.server_port.text()),
       -                                protocol=net_params.server.protocol)
       +            server = ServerAddr.from_str_with_inference(str(self.server_e.text()))
                except Exception:
                    return
                net_params = net_params._replace(server=server,
 (DIR) diff --git a/electrum/interface.py b/electrum/interface.py
       t@@ -65,6 +65,10 @@ BUCKET_NAME_OF_ONION_SERVERS = 'onion'
        
        MAX_INCOMING_MSG_SIZE = 1_000_000  # in bytes
        
       +_KNOWN_NETWORK_PROTOCOLS = {'t', 's'}
       +PREFERRED_NETWORK_PROTOCOL = 's'
       +assert PREFERRED_NETWORK_PROTOCOL in _KNOWN_NETWORK_PROTOCOLS
       +
        
        class NetworkTimeout:
            # seconds
       t@@ -212,7 +216,7 @@ class ServerAddr:
                    net_addr = NetAddress(host, port)  # this validates host and port
                except Exception as e:
                    raise ValueError(f"cannot construct ServerAddr: invalid host or port (host={host}, port={port})") from e
       -        if protocol not in ('s', 't'):
       +        if protocol not in _KNOWN_NETWORK_PROTOCOLS:
                    raise ValueError(f"invalid network protocol: {protocol}")
                self.host = str(net_addr.host)  # canonical form (if e.g. IPv6 address)
                self.port = int(net_addr.port)
       t@@ -225,6 +229,24 @@ class ServerAddr:
                host, port, protocol = str(s).rsplit(':', 2)
                return ServerAddr(host=host, port=port, protocol=protocol)
        
       +    @classmethod
       +    def from_str_with_inference(cls, s: str) -> Optional['ServerAddr']:
       +        """Construct ServerAddr from str, guessing missing details.
       +        Ongoing compatibility not guaranteed.
       +        """
       +        if not s:
       +            return None
       +        items = str(s).rsplit(':', 2)
       +        if len(items) < 2:
       +            return None  # although maybe we could guess the port too?
       +        host = items[0]
       +        port = items[1]
       +        if len(items) >= 3:
       +            protocol = items[2]
       +        else:
       +            protocol = PREFERRED_NETWORK_PROTOCOL
       +        return ServerAddr(host=host, port=port, protocol=protocol)
       +
            def __str__(self):
                return '{}:{}'.format(self.net_addr_str(), self.protocol)
        
 (DIR) diff --git a/electrum/network.py b/electrum/network.py
       t@@ -53,7 +53,7 @@ from . import bitcoin
        from . import dns_hacks
        from .transaction import Transaction
        from .blockchain import Blockchain, HEADER_SIZE
       -from .interface import (Interface,
       +from .interface import (Interface, PREFERRED_NETWORK_PROTOCOL,
                                RequestTimedOut, NetworkTimeout, BUCKET_NAME_OF_ONION_SERVERS,
                                NetworkException, RequestCorrupted, ServerAddr)
        from .version import PROTOCOL_VERSION
       t@@ -75,10 +75,6 @@ NUM_TARGET_CONNECTED_SERVERS = 10
        NUM_STICKY_SERVERS = 4
        NUM_RECENT_SERVERS = 20
        
       -_KNOWN_NETWORK_PROTOCOLS = {'t', 's'}
       -PREFERRED_NETWORK_PROTOCOL = 's'
       -assert PREFERRED_NETWORK_PROTOCOL in _KNOWN_NETWORK_PROTOCOLS
       -
        
        def parse_servers(result: Sequence[Tuple[str, str, List[str]]]) -> Dict[str, dict]:
            """ parse servers list into dict format"""