From e5d28563cc17226aa24fa1439e8196050b50b30e Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sat, 3 Feb 2024 11:30:10 +0000 Subject: [PATCH 1/2] network: implement basic "add server as bookmark" functionality implement backend and expose it to qt gui --- electrum/gui/icons/bookmark.png | Bin 0 -> 455 bytes electrum/gui/icons/bookmark.svg | 11 ++++++++++ electrum/gui/icons/bookmark_add.png | Bin 0 -> 1364 bytes electrum/gui/icons/bookmark_add.svg | 23 ++++++++++++++++++++ electrum/gui/icons/bookmark_remove.png | Bin 0 -> 1352 bytes electrum/gui/icons/bookmark_remove.svg | 23 ++++++++++++++++++++ electrum/gui/qt/network_dialog.py | 11 ++++++++++ electrum/network.py | 28 +++++++++++++++++++++++++ electrum/simple_config.py | 1 + 9 files changed, 97 insertions(+) create mode 100644 electrum/gui/icons/bookmark.png create mode 100644 electrum/gui/icons/bookmark.svg create mode 100644 electrum/gui/icons/bookmark_add.png create mode 100644 electrum/gui/icons/bookmark_add.svg create mode 100644 electrum/gui/icons/bookmark_remove.png create mode 100644 electrum/gui/icons/bookmark_remove.svg diff --git a/electrum/gui/icons/bookmark.png b/electrum/gui/icons/bookmark.png new file mode 100644 index 0000000000000000000000000000000000000000..dd24a0c152127bc938a0818f32e1b32a423708ba GIT binary patch literal 455 zcmeAS@N?(olHy`uVBq!ia0vp^0U*r51|<6gKdl8)oCO|{#S9GG!XV7ZFl&wk0|R5F zr;B4q#hkZy9J3BNFtk3DSrg#FR3+?~pCo1(U>++X|5ldk8;@*(rK;n?Ef>rR-^}Lx z&(B!SH($SNc8I8;;8{OkVefr!!yCpPoeht~o>^a*`$LfN!mJ2| zhHFQd7`Ld2aV#+1=)kbHla(pMS4Y4hJE@T&N|>94I!X#Qa`VKR$Ju;aGM}&fPTu3w zRkm@5UtgKfU6beYV%Lvtw|g_<=No+46Ls|ZS+#xdzcbAH#}t0uzkONe)otagUbh2P zMkM@Te0Te|N}G<9fltG3(Uge|54m<+nc&LU)>5!ip__rnyk)nTQTBlk{RPE}n^}0= zcC4ImlTq&ce;K=jwsN<=-K*XAkmqou-t%35HlO4Rcy`n`Hl?nibY8)J$6e=xpBAk? kw|DE^=L$-zxZW{8+Hu@`!|{4MV9YRhy85}Sb4q9e0DwcaGynhq literal 0 HcmV?d00001 diff --git a/electrum/gui/icons/bookmark.svg b/electrum/gui/icons/bookmark.svg new file mode 100644 index 000000000..32123634d --- /dev/null +++ b/electrum/gui/icons/bookmark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/electrum/gui/icons/bookmark_add.png b/electrum/gui/icons/bookmark_add.png new file mode 100644 index 0000000000000000000000000000000000000000..430861c479c33eb225ddc45c2eb8b90f0fa81a77 GIT binary patch literal 1364 zcmV-a1*`grP)sWISxJ9D1=nerVC3!CGt`I#rjuv zCBQrBKIo9U3P28wbwT%42?mzV!1m&y0Kr;^YzcC-jm5m!TM z$Gf`*;NMab}j)?Cu4N#Y)LaKrrh8;Ck3J_gdP%ITb za4b*MC;-GH*-BOH?zYtcoL#>GtrKx_?FLo+fLVY&W`%)yp567V8i447i>FN$ii=DF z+&p!%P+{0flAQvGia&rAiy}U4kUxEsIe;?*y#yeZXO--z)dED1O(m_gCd?eb^l*L+ z!upjKK)f~yV?`Wi4q%s@Pn@waKnvjHO3vDi?=T1Okdn{EzIixP7NBbFdDp;e=M^Yy zF$b_k$#+RGrJx0H_V;;fCw{^K?lypjcnC{;6QQZV%uu&`(il}Z$8I7$m81rc=|uXE zR00~+2(?mf`nNe~8O@h+jbo8Fm;-2(G!t+DM5~z)QiSiThDWcR^(A=-oSxwTXr};T z`eL=Sf{O6Ik5zz=rDS1{gwwN~0+=)#sv$+Z&vZl8z?S}3`IdguNGFUhU)s@@euEtG zI|7gPP)R8am7-+uQ^}56j$dBA3I~frr9q!(#+s=l#7f4RwSb7{JbdAED|CPG)L7Gy zB>3xJgY_s(*a+vB`S^0KRCy0R%(m}!6rLLZS`cGqpAgq6oSwa?TT|9LQ zg7Q53YKKu0&T7faMVM}2&Sqz7heqdZv>37q8Aj-wp)NlZVr5Dz( zllO9@8Hx%+$7B2&PWSLLq{1k^-ge*7-If)AhM6aRmp%@kWuv6*EBob2MSO}C1}4ez zczjRI;kgxHssEWu!1YWoWQOA8MI`JeVpqFa79c#(PUado9KyzcBekv902(iF{`bNX z2MAn&J|4n+4Ww-v-$Xb-&ni$)B#84gMzRlXqqP-&+P|MT9y<-vlX;+?NWf-W8-cd{ zKMei2Zy&6M!|>0E6C9vX4miJm@pfHZKnn!k*8Ki?r$Kr`f%^Y|`_FY82FWx)-3GW? zfn*Y(UIjR(K{5qUcMzOYAejKD*AQH_AYBbm-$8Jdf^;Q7ogz59AYBJ=!>k-iz%ASk z1m2;2e|QggFV=lom5u8FYLpdcSCQ@m=yxZ$mw}{xKR&mFYNeq~`#!jF + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/electrum/gui/icons/bookmark_remove.png b/electrum/gui/icons/bookmark_remove.png new file mode 100644 index 0000000000000000000000000000000000000000..a75c86c6b37649b28606d66d0eed9aa3d5e13998 GIT binary patch literal 1352 zcmV-O1-JT%P)Y&`ktXSSVY1N%rTNjWSTJpLzL+|iWOdhH2(FH;1GT<$jV}hf><;F3KgWW(~$IYqjdQ{-?q>VJ(=T=5O?zB&oF&J4q)*gKF5%Pn~}EPb2n zmkuoigU|0ufWIe3p?K`A29S$K_dzw;2e-4QpjJwQapgQbs%D7e|Z*PKB zc$1n=)EEFnk!(qoot(C<`lCt)io^8-D<28;atrX1Sz(~g>l8f8*Ru80kyGRqE&&1aR+cYewZvC>sM9) z*RrRqZ9K~zz>+DPu`$33Aj+nCtt|b-9l-hMezN!nS1vsH0%_Y5zQg$DycK~P+yN{^ z0%Y+hDOdsgr<$<(%|xk!Lr zDOa9?xoEwVn+bKl!W}@v)=a{ zt0VQc5)OQD@Y61M`sH)Bp^|*TL(?>d0QJeU@cCfx=2){05Xo3`#2RZ#-??h6X>1v+ zW0c%kN>YP&XK~y<&b&F-*YgrpcuoLlLHxp$HkhYydiKjSryZ|&zorq%l%h(}O_BDTVrTiEx3>3*@V`I;?9iCGG z+Wqg;hw$s^At=Y+v)$qwfIQ~QkVNJhI2^*p0F~O-Z2*m@xcGZvRR9DLfgZ7iMGjZou{_{PQL2?aHZvkApKynFC-vKz + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/electrum/gui/qt/network_dialog.py b/electrum/gui/qt/network_dialog.py index 141987fc8..a47f6528f 100644 --- a/electrum/gui/qt/network_dialog.py +++ b/electrum/gui/qt/network_dialog.py @@ -123,6 +123,13 @@ class NodesListWidget(QTreeWidget): def do_set_server(): self.setServer.emit(str(server)) menu.addAction(read_QIcon("chevron-right.png"), _("Use as server"), do_set_server) + def set_bookmark(*, add: bool): + self.network.set_server_bookmark(server, add=add) + self.update() + if self.network.is_server_bookmarked(server): + menu.addAction(read_QIcon("bookmark_remove.png"), _("Remove from bookmarks"), lambda: set_bookmark(add=False)) + else: + menu.addAction(read_QIcon("bookmark_add.png"), _("Bookmark this server"), lambda: set_bookmark(add=True)) elif item_type == self.ItemType.CHAIN: chain_id = item.data(0, self.CHAIN_ID_ROLE) def do_follow_chain(): @@ -174,6 +181,8 @@ class NodesListWidget(QTreeWidget): item.setToolTip(0, str(i.server)) if i == network.interface: item.setIcon(0, read_QIcon("chevron-right.png")) + elif network.is_server_bookmarked(i.server): + item.setIcon(0, read_QIcon("bookmark.png")) x.addChild(item) if n_chains > 1: connected_servers_item.addChild(x) @@ -195,6 +204,8 @@ class NodesListWidget(QTreeWidget): item = QTreeWidgetItem([server.net_addr_str(), ""]) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER) item.setData(0, self.SERVER_ADDR_ROLE, server) + if network.is_server_bookmarked(server): + item.setIcon(0, read_QIcon("bookmark.png")) disconnected_servers_item.addChild(item) self.addTopLevelItem(connected_servers_item) diff --git a/electrum/network.py b/electrum/network.py index d3c2b1b7e..ddef1aa8f 100644 --- a/electrum/network.py +++ b/electrum/network.py @@ -581,6 +581,18 @@ class Network(Logger, NetworkRetryManager[ServerAddr]): out[server.host].update({server.protocol: port}) else: out[server.host] = {server.protocol: port} + # add bookmarks + bookmarks = self.config.NETWORK_BOOKMARKED_SERVERS or [] + for server_str in bookmarks: + try: + server = ServerAddr.from_str(server_str) + except ValueError: + continue + port = str(server.port) + if server.host in out: + out[server.host].update({server.protocol: port}) + else: + out[server.host] = {server.protocol: port} # potentially filter out some if self.config.NETWORK_NOONION: out = filter_noonion(out) @@ -706,6 +718,22 @@ class Network(Logger, NetworkRetryManager[ServerAddr]): self.oneserver = oneserver self.num_server = NUM_TARGET_CONNECTED_SERVERS if not oneserver else 0 + def is_server_bookmarked(self, server: ServerAddr) -> bool: + bookmarks = self.config.NETWORK_BOOKMARKED_SERVERS or [] + return str(server) in bookmarks + + def set_server_bookmark(self, server: ServerAddr, *, add: bool) -> None: + server_str = str(server) + with self.config.lock: + bookmarks = self.config.NETWORK_BOOKMARKED_SERVERS or [] + if add: + if server_str not in bookmarks: + bookmarks.append(server_str) + else: # remove + if server_str in bookmarks: + bookmarks.remove(server_str) + self.config.NETWORK_BOOKMARKED_SERVERS = bookmarks + async def _switch_to_random_interface(self): '''Switch to a random connected server other than the current one''' servers = self.get_interfaces() # Those in connected state diff --git a/electrum/simple_config.py b/electrum/simple_config.py index 81aa1772f..5486b11d2 100644 --- a/electrum/simple_config.py +++ b/electrum/simple_config.py @@ -934,6 +934,7 @@ class SimpleConfig(Logger): NETWORK_SERVERFINGERPRINT = ConfigVar('serverfingerprint', default=None, type_=str) NETWORK_MAX_INCOMING_MSG_SIZE = ConfigVar('network_max_incoming_msg_size', default=1_000_000, type_=int) # in bytes NETWORK_TIMEOUT = ConfigVar('network_timeout', default=None, type_=int) + NETWORK_BOOKMARKED_SERVERS = ConfigVar('network_bookmarked_servers', default=None) WALLET_BATCH_RBF = ConfigVar( 'batch_rbf', default=False, type_=bool, From 9c6d7617d342a6595c671bdaa562815bcf0edc83 Mon Sep 17 00:00:00 2001 From: SomberNight Date: Sat, 3 Feb 2024 11:42:40 +0000 Subject: [PATCH 2/2] qt NetworkDialog: sort bookmarked servers to top --- electrum/gui/qt/network_dialog.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/electrum/gui/qt/network_dialog.py b/electrum/gui/qt/network_dialog.py index a47f6528f..1ad70a090 100644 --- a/electrum/gui/qt/network_dialog.py +++ b/electrum/gui/qt/network_dialog.py @@ -192,15 +192,16 @@ class NodesListWidget(QTreeWidget): 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]) protocol = PREFERRED_NETWORK_PROTOCOL - for _host, d in sorted(servers.items()): - if _host in connected_hosts: + 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 _host.endswith('.onion') and not use_tor: + if server.host.endswith('.onion') and not use_tor: continue - port = d.get(protocol) - if not port: - continue - server = ServerAddr(_host, port, protocol=protocol) item = QTreeWidgetItem([server.net_addr_str(), ""]) item.setData(0, self.ITEMTYPE_ROLE, self.ItemType.DISCONNECTED_SERVER) item.setData(0, self.SERVER_ADDR_ROLE, server)