diff --git a/Cargo.lock b/Cargo.lock index 6c39007d..772a95d7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4247,18 +4247,17 @@ dependencies = [ [[package]] name = "gvdb" -version = "0.5.3" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb9136c388a1e7b3017d18fe7c2f263b0a2b13f215c48e8eb44935d413ce0f9" +checksum = "d5469af05ff2285b41c9e79a2c7f825cb59dff3b22791befe1aec0c8ab987791" dependencies = [ - "byteorder", "flate2", - "quick-xml", - "safe-transmute", + "quick-xml 0.36.2", "serde", "serde_json", "walkdir", - "zvariant 3.7.1", + "zerocopy", + "zvariant", ] [[package]] @@ -8776,6 +8775,15 @@ name = "quick-xml" version = "0.31.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1004a344b30a54e2ee58d66a71b32d2db2feb0a31f9a2d302bf0536f15de2a33" +dependencies = [ + "memchr", +] + +[[package]] +name = "quick-xml" +version = "0.36.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7649a7b4df05aed9ea7ec6f628c67c9953a43869b8bc50929569b2999d443fe" dependencies = [ "memchr", "serde", @@ -9252,18 +9260,18 @@ checksum = "1d3b924557df1cddc687b60b313c4b76620fdbf0e463afa4b29f67193ccf37f9" [[package]] name = "relm4-icons" -version = "0.10.0-beta.1" +version = "0.10.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4b1a664ccea4662eea207c48191d403b46ea512eb385b8f7f571a1a45a0dda" +checksum = "929f301d6723d8d1fa443d764b3a1d864b287d3cb0beb889500b39cf714d5e81" dependencies = [ "gtk4", ] [[package]] name = "relm4-icons-build" -version = "0.10.0-beta.1" +version = "0.10.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a085f4290a4820566b547621859f0acb388cb493cf10f0e4c7293a471fc695e" +checksum = "11ffa92b81d7b55dc115e5c8555df3e585a8aec3648862e821da81a0ce0cebd3" dependencies = [ "gvdb", "serde", @@ -9684,12 +9692,6 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" -[[package]] -name = "safe-transmute" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3944826ff8fa8093089aba3acb4ef44b9446a99a16f3bf4e74af3f77d340ab7d" - [[package]] name = "safe_arch" version = "0.7.2" @@ -10924,9 +10926,9 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.213" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -10951,9 +10953,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.213" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", @@ -10962,9 +10964,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -12991,7 +12993,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f89f5fb70d6f62381f5d9b2ba9008196150b40b75f3068eb24faeddf1c686871" dependencies = [ - "quick-xml", + "quick-xml 0.31.0", "windows 0.56.0", "windows-version", ] @@ -14961,7 +14963,7 @@ dependencies = [ "xdg-home", "zbus_macros", "zbus_names", - "zvariant 4.2.0", + "zvariant", ] [[package]] @@ -14985,7 +14987,7 @@ checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" dependencies = [ "serde", "static_assertions", - "zvariant 4.2.0", + "zvariant", ] [[package]] @@ -15119,19 +15121,6 @@ dependencies = [ "zune-core", ] -[[package]] -name = "zvariant" -version = "3.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794fb7f59af4105697b0449ba31731ee5dbb3e773a17dbdf3d36206ea1b1644" -dependencies = [ - "byteorder", - "libc", - "serde", - "static_assertions", - "zvariant_derive 3.7.1", -] - [[package]] name = "zvariant" version = "4.2.0" @@ -15142,19 +15131,7 @@ dependencies = [ "enumflags2", "serde", "static_assertions", - "zvariant_derive 4.2.0", -] - -[[package]] -name = "zvariant_derive" -version = "3.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd58d4b6c8e26d3dd2149c8c40c6613ef6451b9885ff1296d1ac86c388351a54" -dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2", - "quote", - "syn 1.0.109", + "zvariant_derive", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index acaa4688..10ef3685 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -67,7 +67,7 @@ parity-scale-codec = "3.6.12" parking_lot = "0.12.3" relm4 = "0.9.1" relm4-components = { version = "0.9.1", default-features = false } -relm4-icons = "0.10.0-beta.0" +relm4-icons = "0.10.0-beta.2" reqwest = { version = "0.12.8", default-features = false, features = ["json", "rustls-tls"] } sc-client-api = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false } sc-client-db = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false } @@ -82,8 +82,8 @@ sc-subspace-chain-specs = { git = "https://github.com/subspace/subspace", rev = sc-utils = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false } schnellru = "0.2.3" semver = "1.0.23" -serde = { version = "1.0.213", features = ["derive"] } -serde_json = "1.0.132" +serde = { version = "1.0.215", features = ["derive"] } +serde_json = "1.0.133" simple_moving_average = "1.0.2" sp-api = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false } sp-consensus = { git = "https://github.com/subspace/polkadot-sdk", rev = "94a1a8143a89bbe9f938c1939ff68abc1519a305", default-features = false } @@ -126,7 +126,7 @@ ksni = "0.2.2" [build-dependencies] fluent-static-codegen = "0.5.0" -relm4-icons-build = "0.10.0-beta.0" +relm4-icons-build = "0.10.0-beta.2" [target.'cfg(windows)'.build-dependencies] winres = "0.1.12" diff --git a/build.rs b/build.rs index ef64349f..982ddfa3 100644 --- a/build.rs +++ b/build.rs @@ -35,20 +35,26 @@ fn main() { None, None::<&str>, [ - "ssd", - "size-horizontally", - "cross", + "cross-small", "checkmark", - "wallet2", - "warning", + "grid-filled", "puzzle-piece", "pause", "menu-large", "processor", - "speedometer2", - "speedometer3", - "speedometer4", - "grid-filled", + "size-horizontally", + "speedometer-low", + "speedometer-medium", + "speedometer-high", + "ssd", + "strength-bars-1", + "strength-nars-2", + "strength-bars-3", + "strength-bars-4", + "strength-bars-5", + "strength-bars-6", + "wallet2", + "warning-outline", ], ); } diff --git a/res/translations/de-DE/messages.ftl b/res/translations/de-DE/messages.ftl index 660e2dd0..c005c658 100644 --- a/res/translations/de-DE/messages.ftl +++ b/res/translations/de-DE/messages.ftl @@ -98,6 +98,8 @@ running_title = Wird ausgeführt running_node_title = {$chain_name} Konsens-Node running_node_title_tooltip = Klicken, um im Dateimanager zu öffnen running_node_free_disk_space_tooltip = Freier Speicherplatz: {$size} verbleibend +# TODO: Translate +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} peers connected, click for details about required P2P ports running_node_status_connecting = Verbindung zum Netzwerk wird hergestellt, bester Block #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blocks/s running_node_status_syncing_speed_hours_eta = , {NUMBER($a_blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blocks/s (~{NUMBER($b_hours_remaining, minimumFractionDigits: 2, maximumFractionDigits: 2)} hours remaining) diff --git a/res/translations/en/messages.ftl b/res/translations/en/messages.ftl index cc260b9f..ef9eea48 100644 --- a/res/translations/en/messages.ftl +++ b/res/translations/en/messages.ftl @@ -97,6 +97,7 @@ running_title = Running running_node_title = {$chain_name} consensus node running_node_title_tooltip = Click to open in file manager running_node_free_disk_space_tooltip = Free disk space: {$size} remaining +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} peers connected, click for details about required P2P ports running_node_status_connecting = Connecting to the network, best block #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blocks/s running_node_status_syncing_speed_hours_eta = , {NUMBER($a_blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blocks/s (~{NUMBER($b_hours_remaining, minimumFractionDigits: 2, maximumFractionDigits: 2)} hours remaining) diff --git a/res/translations/es/messages.ftl b/res/translations/es/messages.ftl index 7f74563d..5facb372 100644 --- a/res/translations/es/messages.ftl +++ b/res/translations/es/messages.ftl @@ -96,6 +96,8 @@ configuration_dialog_button_cancel = Cancelar running_title = Ejecutando running_node_title = {$chain_name} nodo de consenso running_node_title_tooltip = Abrir sistema de archivos +# TODO: Translate +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} peers connected, click for details about required P2P ports running_node_free_disk_space_tooltip = Espacio libre en disco: {$size} restante running_node_status_connecting = Conectando a la red, mejor bloque #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} bloques/s diff --git a/res/translations/fr/messages.ftl b/res/translations/fr/messages.ftl index 15a7361d..f9e25fa0 100644 --- a/res/translations/fr/messages.ftl +++ b/res/translations/fr/messages.ftl @@ -96,6 +96,8 @@ configuration_dialog_button_cancel = Annuler running_title = En cours running_node_title = {$chain_name} Nœud de la blockchain running_node_title_tooltip = Cliquez pour ouvrir dans le gestionnaire de fichiers +# TODO: Translate +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} peers connected, click for details about required P2P ports running_node_free_disk_space_tooltip = Espace disque libre restant : {$size} running_node_status_connecting = Connexion au réseau, meilleur bloc #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blocs/s diff --git a/res/translations/rs/messages.ftl b/res/translations/rs/messages.ftl index 0ccb47b5..5bf6705f 100644 --- a/res/translations/rs/messages.ftl +++ b/res/translations/rs/messages.ftl @@ -99,6 +99,8 @@ configuration_dialog_button_cancel = Otkaži running_title = U radu running_node_title = {$chain_name} konsenzus čvor running_node_title_tooltip = Kliknite da otvorite u upravitelju datotekama +# TODO: Translate +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} peers connected, click for details about required P2P ports running_node_free_disk_space_tooltip = Slobodan prostor na disku: preostalo {$size} running_node_status_connecting = Povezivanje sa mrežom, najbolji blok #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blokova/s diff --git a/res/translations/ru-RU/messages.ftl b/res/translations/ru-RU/messages.ftl index 703fc840..c7830622 100644 --- a/res/translations/ru-RU/messages.ftl +++ b/res/translations/ru-RU/messages.ftl @@ -96,6 +96,7 @@ configuration_dialog_button_cancel = Отмена running_title = Запущено running_node_title = Узел блокчейна {$chain_name} running_node_title_tooltip = Нажмите, чтобы открыть в файловом менеджере +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} подключенных пиров, нажмите для подробностей про нужные P2P порты running_node_free_disk_space_tooltip = Осталось свободного места на диске: {$size} running_node_status_connecting = Подключение к сети, лучший блок #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} блоков/сек diff --git a/res/translations/uk-UA/messages.ftl b/res/translations/uk-UA/messages.ftl index 00112bd5..76cc6a71 100644 --- a/res/translations/uk-UA/messages.ftl +++ b/res/translations/uk-UA/messages.ftl @@ -94,6 +94,7 @@ configuration_dialog_button_cancel = Скасувати running_title = Запущено running_node_title = {$chain_name} вузол консенсусу running_node_title_tooltip = Натисніть щоб відкрити в файловому менеджері +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} пірів підключено, натисніть для деталей про необхідні P2P порти running_node_free_disk_space_tooltip = Вільний дисковий простір: {$size} remaining running_node_status_connecting = Підключення до мережі, кращий блок #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} блоки/с diff --git a/res/translations/zh-CN/messages.ftl b/res/translations/zh-CN/messages.ftl index d9c54c20..f6240998 100644 --- a/res/translations/zh-CN/messages.ftl +++ b/res/translations/zh-CN/messages.ftl @@ -98,6 +98,8 @@ configuration_dialog_button_cancel = 取消 running_title = 运行中 running_node_title = {$chain_name} 共识节点 running_node_title_tooltip = 在文件管理器中打开 +# TODO: Translate +running_node_connections_tooltip = {$connected_peers}/{$expected_peers} peers connected, click for details about required P2P ports running_node_free_disk_space_tooltip = 空闲磁盘大小: {$size} running_node_status_connecting = 连接网络中,最新区块 #{$block_number} running_node_status_syncing_speed_no_eta = , {NUMBER($blocks_per_second, minimumFractionDigits: 2, maximumFractionDigits: 2)} blocks/s diff --git a/src/backend.rs b/src/backend.rs index 5b699762..9d356154 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -237,6 +237,7 @@ enum LoadedConsensusChainNode { #[derive(Debug, Clone)] pub enum NodeNotification { SyncStateUpdate(SyncState), + ConnectedPeersUpdate(u32), BlockImported(BlockImportedNotification), } @@ -561,6 +562,26 @@ async fn run( } }) }); + let _on_connected_peers_change_handler_id = consensus_node.on_connected_peers_change({ + let notifications_sender = notifications_sender.clone(); + + Arc::new(move |&connected_peers| { + let notification = NodeNotification::ConnectedPeersUpdate(connected_peers); + + let mut notifications_sender = notifications_sender.clone(); + + if let Err(error) = notifications_sender + .try_send(BackendNotification::Node(notification)) + .or_else(|error| { + tokio::task::block_in_place(|| { + Handle::current().block_on(notifications_sender.send(error.into_inner())) + }) + }) + { + warn!(%error, "Failed to send sync state backend notification"); + } + }) + }); let _on_imported_block_handler_id = consensus_node.on_block_imported({ let notifications_sender = notifications_sender.clone(); diff --git a/src/backend/node.rs b/src/backend/node.rs index e6a40830..23a4b322 100644 --- a/src/backend/node.rs +++ b/src/backend/node.rs @@ -51,9 +51,14 @@ use tracing::{error, info, info_span}; pub(super) const GENESIS_HASH: &str = "66455a580aabff303720aa83adbe6c44502922251c03ba73686d5245da9e21bd"; const SYNC_STATUS_EVENT_INTERVAL: Duration = Duration::from_secs(5); +const CONNECTED_PEERS_EVENT_INTERVAL: Duration = Duration::from_secs(5); /// Roughly 138k empty blocks can fit into one archived segment, hence we need to not allow to prune /// more blocks that this const MIN_STATE_PRUNING: BlockNumber = 140_000; +// Substrate's default +pub const IN_PEERS: u32 = 32; +// Substrate's default +pub const OUT_PEERS: u32 = 8; /// The maximum number of characters for a node name. const NODE_NAME_MAX_LENGTH: usize = 64; @@ -132,6 +137,7 @@ pub struct BlockImportedNotification { #[derive(Default, Debug)] struct Handlers { sync_state_change: Handler, + connected_peers_change: Handler, block_imported: Handler, } @@ -244,6 +250,29 @@ impl ConsensusNode { } } }; + let connected_peers_notification_fut = async { + let mut sync_status_interval = tokio::time::interval(CONNECTED_PEERS_EVENT_INTERVAL); + sync_status_interval.set_missed_tick_behavior(MissedTickBehavior::Skip); + + let mut last_connected_peers = 0; + self.handlers + .connected_peers_change + .call_simple(&last_connected_peers); + + loop { + sync_status_interval.tick().await; + + let connected_peers = self.full_node.sync_service.num_connected_peers() as u32; + + if connected_peers != last_connected_peers { + self.handlers + .connected_peers_change + .call_simple(&connected_peers); + + last_connected_peers = connected_peers; + } + } + }; let task_manager = self.full_node.task_manager.future(); @@ -254,6 +283,9 @@ impl ConsensusNode { _ = sync_status_notifications_fut.fuse() => { // Nothing else to do } + _ = connected_peers_notification_fut.fuse() => { + // Nothing else to do + } } Ok(()) @@ -286,6 +318,10 @@ impl ConsensusNode { self.handlers.sync_state_change.add(callback) } + pub(super) fn on_connected_peers_change(&self, callback: HandlerFn) -> HandlerId { + self.handlers.connected_peers_change.add(callback) + } + pub(super) fn on_block_imported( &self, callback: HandlerFn, @@ -428,10 +464,8 @@ fn create_consensus_chain_config( .expect("Correct secret; qed"), )), default_peers_set: SetConfig { - // Substrate's default - in_peers: 8, - // Substrate's default - out_peers: 32, + in_peers: IN_PEERS, + out_peers: OUT_PEERS, reserved_nodes: Vec::new(), non_reserved_mode: NonReservedPeerMode::Accept, }, diff --git a/src/frontend/configuration.rs b/src/frontend/configuration.rs index b7894157..eefbcc61 100644 --- a/src/frontend/configuration.rs +++ b/src/frontend/configuration.rs @@ -106,7 +106,7 @@ where if self.is_valid { Some(icon_names::CHECKMARK) } else { - Some(icon_names::CROSS) + Some(icon_names::CROSS_SMALL) } } } diff --git a/src/frontend/configuration/farm.rs b/src/frontend/configuration/farm.rs index eeea99d6..24d48e62 100644 --- a/src/frontend/configuration/farm.rs +++ b/src/frontend/configuration/farm.rs @@ -254,7 +254,7 @@ impl AsyncFactoryComponent for FarmWidget { warn!("Can't send delete output"); } }, - set_icon_name: icon_names::CROSS, + set_icon_name: icon_names::CROSS_SMALL, set_tooltip: &T.configuration_farm_delete(), }, }, diff --git a/src/frontend/running.rs b/src/frontend/running.rs index f144a2f7..e47ce07b 100644 --- a/src/frontend/running.rs +++ b/src/frontend/running.rs @@ -384,6 +384,9 @@ impl RunningView { } self.set_node_synced(new_synced); } + NodeNotification::ConnectedPeersUpdate(_) => { + // Ignore + } NodeNotification::BlockImported(imported_block) => { if !self.node_synced { // Do not count balance increase during sync as increase related to diff --git a/src/frontend/running/farm.rs b/src/frontend/running/farm.rs index 78b7cf84..46f8f258 100644 --- a/src/frontend/running/farm.rs +++ b/src/frontend/running/farm.rs @@ -177,7 +177,7 @@ impl FactoryComponent for FarmWidget { set_hexpand: true, gtk::Image { - set_icon_name: Some(icon_names::WARNING), + set_icon_name: Some(icon_names::WARNING_OUTLINE), } }, None => { @@ -215,9 +215,9 @@ impl FactoryComponent for FarmWidget { gtk::Image { #[track = "self.changed_proving_result() || self.changed_auditing_time_score() || self.changed_proving_time_score()"] set_icon_name: Some(match self.farm_score() { - ..=0.4 => icon_names::SPEEDOMETER4, - ..=0.8 => icon_names::SPEEDOMETER3, - _ => icon_names::SPEEDOMETER2, + ..=0.4 => icon_names::SPEEDOMETER_HIGH, + ..=0.8 => icon_names::SPEEDOMETER_MEDIUM, + _ => icon_names::SPEEDOMETER_LOW, }), }, }, @@ -271,7 +271,7 @@ impl FactoryComponent for FarmWidget { }, gtk::Image { - set_icon_name: Some(icon_names::WARNING), + set_icon_name: Some(icon_names::WARNING_OUTLINE), #[track = "self.changed_non_fatal_farming_error()"] set_tooltip: { let last_error = self.non_fatal_farming_error diff --git a/src/frontend/running/node.rs b/src/frontend/running/node.rs index e2502aef..a468db0a 100644 --- a/src/frontend/running/node.rs +++ b/src/frontend/running/node.rs @@ -1,4 +1,4 @@ -use crate::backend::node::{ChainInfo, SyncState}; +use crate::backend::node::{ChainInfo, SyncState, IN_PEERS, OUT_PEERS}; use crate::backend::NodeNotification; use crate::frontend::translations::{AsDefaultStr, T}; use crate::icon_names; @@ -23,6 +23,8 @@ const FREE_DISK_SPACE_CHECK_INTERVAL: Duration = Duration::from_secs(5); const FREE_DISK_SPACE_CHECK_WARNING_THRESHOLD: u64 = ByteSize::gib(10).as_u64(); /// Number of samples over which to track block import time, 1 minute in slots const BLOCK_IMPORT_TIME_TRACKING_WINDOW: usize = 1000; +const ALL_PEERS: u32 = OUT_PEERS + IN_PEERS; +const ALMOST_ALL_PEERS: u32 = OUT_PEERS + IN_PEERS - IN_PEERS / 5; #[derive(Debug)] pub enum NodeInput { @@ -33,6 +35,7 @@ pub enum NodeInput { }, NodeNotification(NodeNotification), OpenNodeFolder, + OpenP2pPortsDocs, } #[derive(Debug)] @@ -45,6 +48,7 @@ pub enum NodeCommandOutput { pub struct NodeView { best_block_number: BlockNumber, sync_state: SyncState, + connected_peers: u32, free_disk_space: Option, chain_name: String, #[no_eq] @@ -120,6 +124,59 @@ impl Component for NodeView { }, }, }, + + gtk::Button { + // TODO: Use LinkButton once https://gitlab.gnome.org/GNOME/glib/-/issues/3403 is fixed + // for macOS + connect_clicked => NodeInput::OpenP2pPortsDocs, + remove_css_class: "link", + set_cursor_from_name: Some("pointer"), + #[track = "model.changed_connected_peers()"] + set_css_classes: &[ + "flat", + match model.connected_peers { + ALL_PEERS => "success-label", + ..OUT_PEERS => "error-label", + _ => "warning-label", + }, + ], + set_has_frame: false, + #[track = "model.changed_connected_peers()"] + set_tooltip: T + .running_node_connections_tooltip( + model.connected_peers, + IN_PEERS + OUT_PEERS, + ) + .as_str(), + // TODO: Use LinkButton once https://gitlab.gnome.org/GNOME/glib/-/issues/3403 is fixed + // for macOS + // #[watch] + // set_uri: "https://docs.autonomys.xyz/farming/guides/port-config", + set_use_underline: false, + + gtk::Box { + set_spacing: 5, + + gtk::Label { + #[track = "model.changed_connected_peers()"] + set_label: &format!("{}/{}", model.connected_peers, IN_PEERS + OUT_PEERS), + }, + + gtk::Image { + #[track = "model.changed_connected_peers()"] + set_icon_name: + #[expect(clippy::match_overlapping_arm, reason = "Intentional for improved readability")] + Some(match model.connected_peers { + ALL_PEERS => icon_names::STRENGTH_BARS_1, + 0 => icon_names::STRENGTH_BARS_6, + ..OUT_PEERS => icon_names::STRENGTH_BARS_5, + OUT_PEERS => icon_names::STRENGTH_BARS_4, + ..=ALMOST_ALL_PEERS => icon_names::STRENGTH_BARS_3, + _ => icon_names::STRENGTH_NARS_2, + }), + }, + }, + }, }, #[transition = "SlideUpDown"] @@ -227,6 +284,7 @@ impl Component for NodeView { let model = Self { best_block_number: 0, sync_state: SyncState::default(), + connected_peers: 0, free_disk_space: None, chain_name: String::new(), node_path: node_path.clone(), @@ -313,6 +371,9 @@ impl NodeView { } self.set_sync_state(new_sync_state); } + NodeNotification::ConnectedPeersUpdate(connected_peers) => { + self.set_connected_peers(connected_peers); + } NodeNotification::BlockImported(imported_block) => { self.set_best_block_number(imported_block.number); // Ensure target is never below current block @@ -334,6 +395,13 @@ impl NodeView { error!(%error, path = %node_path.display(), "Failed to open node folder"); } } + NodeInput::OpenP2pPortsDocs => { + if let Err(error) = + open::that_detached("https://docs.autonomys.xyz/farming/guides/port-config") + { + error!(%error, "Failed to P2P ports docs"); + } + } } }