From c6616a6ad92fcaf8555318983fb95436c3a3c695 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Thu, 29 Aug 2024 16:17:02 +0100 Subject: [PATCH 01/35] chore(release): release candidate 2024.09.1.1 ====================== New Crate Versions ====================== sn_auditor: 0.3.0-rc.1 sn_build_info: 0.1.12-rc.1 sn_cli: 0.95.0-rc.1 sn_client: 0.110.0-rc.1 sn_faucet: 0.5.0-rc.1 sn_logging: 0.2.33-rc.1 sn_metrics: 0.1.13-rc.1 nat-detection: 0.2.3-rc.1 sn_networking: 0.18.0-rc.1 sn_node: 0.111.0-rc.1 node-launchpad: 0.3.13-rc.1 sn_node_manager: 0.10.3-rc.1 sn_node_rpc_client: 0.6.28-rc.1 sn_peers_acquisition: 0.5.0-rc.1 sn_protocol: 0.17.8-rc.1 sn_registers: 0.3.18-rc.1 sn_service_management: 0.3.11-rc.1 sn_transfers: 0.19.0-rc.1 test_utils: 0.4.4-rc.1 token_supplies: 0.1.51-rc.1 ======================= New Binary Versions ======================= faucet: 0.5.0-rc.1 nat-detection: 0.2.3-rc.1 node-launchpad: 0.3.13-rc.1 safe: 0.95.0-rc.1 safenode: 0.111.0-rc.1 safenode-manager: 0.10.3-rc.1 safenode_rpc_client: 0.6.28-rc.1 safenodemand: 0.10.3-rc.1 sn_auditor: 0.3.0-rc.1 --- Cargo.lock | 40 ++++++++++++++++---------------- nat-detection/Cargo.toml | 4 ++-- node-launchpad/Cargo.toml | 8 +++---- release-cycle-info | 4 ++-- sn_auditor/Cargo.toml | 8 +++---- sn_build_info/Cargo.toml | 2 +- sn_cli/Cargo.toml | 14 +++++------ sn_client/Cargo.toml | 18 +++++++------- sn_faucet/Cargo.toml | 16 ++++++------- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 10 ++++---- sn_node/Cargo.toml | 24 +++++++++---------- sn_node_manager/Cargo.toml | 12 +++++----- sn_node_rpc_client/Cargo.toml | 16 ++++++------- sn_peers_acquisition/Cargo.toml | 4 ++-- sn_protocol/Cargo.toml | 8 +++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++---- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 2 +- token_supplies/Cargo.toml | 2 +- 22 files changed, 104 insertions(+), 104 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ee457dce8b..2643369385 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4558,7 +4558,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.2" +version = "0.2.3-rc.1" dependencies = [ "clap", "clap-verbosity-flag", @@ -4673,7 +4673,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.3.12" +version = "0.3.13-rc.1" dependencies = [ "ansi-to-tui", "atty", @@ -6920,7 +6920,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.10.2" +version = "0.10.3-rc.1" dependencies = [ "assert_cmd", "assert_fs", @@ -6982,7 +6982,7 @@ dependencies = [ [[package]] name = "sn_auditor" -version = "0.2.4" +version = "0.3.0-rc.1" dependencies = [ "blsttc", "clap", @@ -7016,14 +7016,14 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.11" +version = "0.1.12-rc.1" dependencies = [ "vergen", ] [[package]] name = "sn_cli" -version = "0.94.1" +version = "0.95.0-rc.1" dependencies = [ "aes 0.7.5", "base64 0.22.1", @@ -7065,7 +7065,7 @@ dependencies = [ [[package]] name = "sn_client" -version = "0.109.1" +version = "0.110.0-rc.1" dependencies = [ "assert_matches", "async-trait", @@ -7148,7 +7148,7 @@ dependencies = [ [[package]] name = "sn_faucet" -version = "0.4.32" +version = "0.5.0-rc.1" dependencies = [ "assert_fs", "base64 0.22.1", @@ -7180,7 +7180,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.32" +version = "0.2.33-rc.1" dependencies = [ "chrono", "color-eyre", @@ -7205,7 +7205,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.12" +version = "0.1.13-rc.1" dependencies = [ "clap", "color-eyre", @@ -7219,7 +7219,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.17.2" +version = "0.18.0-rc.1" dependencies = [ "aes-gcm-siv", "async-trait", @@ -7262,7 +7262,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.110.1" +version = "0.111.0-rc.1" dependencies = [ "assert_fs", "assert_matches", @@ -7316,7 +7316,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.27" +version = "0.6.28-rc.1" dependencies = [ "assert_fs", "async-trait", @@ -7343,7 +7343,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.4.2" +version = "0.5.0-rc.1" dependencies = [ "clap", "lazy_static", @@ -7359,7 +7359,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.7" +version = "0.17.8-rc.1" dependencies = [ "blsttc", "bytes", @@ -7388,7 +7388,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.3.17" +version = "0.3.18-rc.1" dependencies = [ "blsttc", "crdts", @@ -7405,7 +7405,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.3.10" +version = "0.3.11-rc.1" dependencies = [ "async-trait", "dirs-next", @@ -7431,7 +7431,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.18.10" +version = "0.19.0-rc.1" dependencies = [ "assert_fs", "blsttc", @@ -7770,7 +7770,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.3" +version = "0.4.4-rc.1" dependencies = [ "color-eyre", "dirs-next", @@ -7902,7 +7902,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.50" +version = "0.1.51-rc.1" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 914cc1f349..85bfa484cd 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.2" +version = "0.2.3-rc.1" [[bin]] name = "nat-detection" @@ -28,7 +28,7 @@ libp2p = { version = "0.53", features = [ "macros", "upnp", ] } -sn_networking = { path = "../sn_networking", version = "0.17.2" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.1" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 74c2f37ad9..1da1f8e366 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.3.12" +version = "0.3.13-rc.1" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -48,10 +48,10 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn-node-manager = { version = "0.10.2", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.4.2", path = "../sn_peers_acquisition" } +sn-node-manager = { version = "0.10.3-rc.1", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.0-rc.1", path = "../sn_peers_acquisition" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.3.10", path = "../sn_service_management" } +sn_service_management = { version = "0.3.11-rc.1", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/release-cycle-info b/release-cycle-info index df33ca2ed8..14b23f7ad5 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -6,5 +6,5 @@ # # Both of these numbers are used in the packaged version number, which is a collective version # number for all the released binaries. -release-cycle: 2 -release-cycle-counter: 3 +release-cycle: 1 +release-cycle-counter: 1 diff --git a/sn_auditor/Cargo.toml b/sn_auditor/Cargo.toml index 3aa7408673..d4aaef5fc5 100644 --- a/sn_auditor/Cargo.toml +++ b/sn_auditor/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Network Auditor" name = "sn_auditor" -version = "0.2.4" +version = "0.3.0-rc.1" edition = "2021" homepage = "https://maidsafe.net" repository = "https://github.com/maidsafe/safe_network" @@ -31,9 +31,9 @@ graphviz-rust = { version = "0.9.0", optional = true } lazy_static = "1.4.0" serde = { version = "1.0.133", features = ["derive", "rc"] } serde_json = "1.0.108" -sn_client = { path = "../sn_client", version = "0.109.1" } -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } tiny_http = { version = "0.12", features = ["ssl-rustls"] } tracing = { version = "~0.1.26" } tokio = { version = "1.32.0", features = [ diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index 5f7234d406..3ae96627e0 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.11" +version = "0.1.12-rc.1" [build-dependencies] vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } diff --git a/sn_cli/Cargo.toml b/sn_cli/Cargo.toml index 47a2dd6de3..f576dcec0f 100644 --- a/sn_cli/Cargo.toml +++ b/sn_cli/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_cli" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.94.1" +version = "0.95.0-rc.1" [[bin]] path = "src/bin/main.rs" @@ -58,11 +58,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ rmp-serde = "1.1.1" rpassword = "7.3.1" serde = { version = "1.0.133", features = ["derive"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.11" } -sn_client = { path = "../sn_client", version = "0.109.1" } -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } tempfile = "3.6.0" tiny-keccak = "~2.0.2" tokio = { version = "1.32.0", features = [ @@ -84,7 +84,7 @@ eyre = "0.6.8" criterion = "0.5.1" tempfile = "3.6.0" rand = { version = "~0.8.5", features = ["small_rng"] } -sn_client = { path = "../sn_client", version = "0.109.1", features = [ +sn_client = { path = "../sn_client", version = "0.110.0-rc.1", features = [ "test-utils", ] } diff --git a/sn_client/Cargo.toml b/sn_client/Cargo.toml index b1fd1be42a..690c71fc3c 100644 --- a/sn_client/Cargo.toml +++ b/sn_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.109.1" +version = "0.110.0-rc.1" [features] default = [] @@ -49,16 +49,16 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.17.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7" } -sn_registers = { path = "../sn_registers", version = "0.3.17" } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } tempfile = "3.6.0" thiserror = "1.0.23" tiny-keccak = "~2.0.2" tracing = { version = "~0.1.26" } xor_name = "5.0.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2", optional = true } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1", optional = true } eyre = { version = "0.6.8", optional = true } [dev-dependencies] @@ -67,8 +67,8 @@ dirs-next = "~2.0.0" # add rand to libp2p libp2p-identity = { version = "0.2.7", features = ["rand"] } sn_client = { path = "../sn_client", features = ["test-utils"] } -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_registers = { path = "../sn_registers", version = "0.3.17", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1", features = [ "test-utils", ] } @@ -83,7 +83,7 @@ crate-type = ["cdylib", "rlib"] getrandom = { version = "0.2.12", features = ["js"] } wasm-bindgen = "0.2.90" wasm-bindgen-futures = "0.4.40" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } console_error_panic_hook = "0.1.6" tracing-wasm = "0.2.1" wasmtimer = "0.2.0" diff --git a/sn_faucet/Cargo.toml b/sn_faucet/Cargo.toml index f6520473fa..284bfb1615 100644 --- a/sn_faucet/Cargo.toml +++ b/sn_faucet/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_faucet" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.32" +version = "0.5.0-rc.1" [features] default = ["gifting"] @@ -37,13 +37,13 @@ indicatif = { version = "0.17.5", features = ["tokio"] } minreq = { version = "2.11.0", features = ["https-rustls"], optional = true } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" -sn_build_info = { path = "../sn_build_info", version = "0.1.11" } -sn_cli = { path = "../sn_cli", version = "0.94.1" } -sn_client = { path = "../sn_client", version = "0.109.1" } -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7" } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } +sn_cli = { path = "../sn_cli", version = "0.95.0-rc.1" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } tokio = { version = "1.32.0", features = ["parking_lot", "rt"] } tracing = { version = "~0.1.26" } url = "2.5.0" diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 63a149c2e8..4d56e4e5e2 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.32" +version = "0.2.33-rc.1" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index 47154778ba..b09fcf7275 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.12" +version = "0.1.13-rc.1" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index 08ce99805c..e3934ceddb 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.2" +version = "0.18.0-rc.1" [features] default = [] @@ -53,10 +53,10 @@ rand = { version = "~0.8.5", features = ["small_rng"] } rayon = "1.8.0" rmp-serde = "1.1.1" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path="../sn_build_info", version = "0.1.11" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7" } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } -sn_registers = { path = "../sn_registers", version = "0.3.17" } +sn_build_info = { path="../sn_build_info", version = "0.1.12-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index 92c24e07de..a1b40abfe1 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.110.1" +version = "0.111.0-rc.1" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -50,14 +50,14 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.11" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_networking = { path = "../sn_networking", version = "0.17.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7" } -sn_registers = { path = "../sn_registers", version = "0.3.17" } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } -sn_service_management = { path = "../sn_service_management", version = "0.3.10" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.1" } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ "io-util", @@ -84,11 +84,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_client = { path = "../sn_client", version = "0.109.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7", features = [ +sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.18.10", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 732b560319..964e8a6cea 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.10.2" +version = "0.10.3-rc.1" [[bin]] name = "safenode-manager" @@ -44,12 +44,12 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7" } -sn_service_management = { path = "../sn_service_management", version = "0.3.10" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.1" } sn-releases = "0.2.6" -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index e38f8dfb2a..6c8f9cb0c4 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.27" +version = "0.6.28-rc.1" [[bin]] name = "safenode_rpc_client" @@ -23,13 +23,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version="0.53", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_client = { path = "../sn_client", version = "0.109.1" } -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_node = { path = "../sn_node", version = "0.110.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.4.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.3.10" } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_node = { path = "../sn_node", version = "0.111.0-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index 79c03be459..df24200840 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.2" +version = "0.5.0-rc.1" [features] local-discovery = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version="0.53", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.7", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false} tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index ad3785876f..e0208860d0 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.7" +version = "0.17.8-rc.1" [features] default = [] @@ -28,9 +28,9 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.11" } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } -sn_registers = { path = "../sn_registers", version = "0.3.17" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index f1a80ab393..322cac35a4 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.17" +version = "0.3.18-rc.1" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index f3ccfe6acc..f33caa5e49 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.10" +version = "0.3.11-rc.1" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.32" } -sn_protocol = { path = "../sn_protocol", version = "0.17.7", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.18.10" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index 6b009d51fb..91e85a9423 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.18.10" +version = "0.19.0-rc.1" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 5dfe93d186..1f54157a93 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.3" +version = "0.4.4-rc.1" [dependencies] color-eyre = "~0.6.2" diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index 7b5b640541..66e1ae054b 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.50" +version = "0.1.51-rc.1" [dependencies] From ffbff24881a327fbf97ec2e6ff77980b46fb61bb Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Thu, 29 Aug 2024 16:51:30 +0100 Subject: [PATCH 02/35] chore: read release cycle year and month from file The year and month for the release cycle are now provided from file rather than being read from the OS. For an explanation, see the comment in the diff. --- .github/workflows/release.yml | 5 +++-- Justfile | 5 +++-- release-cycle-info | 8 ++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d76079329b..fd095472c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -190,10 +190,11 @@ jobs: - name: set package version shell: bash run: | - current_date=$(date +%Y.%m) + release_year=$(grep 'release-year:' release-cycle-info | awk '{print $2}') + release_month=$(grep 'release-month:' release-cycle-info | awk '{print $2}') release_cycle=$(grep 'release-cycle:' release-cycle-info | awk '{print $2}') release_cycle_counter=$(grep 'release-cycle-counter:' release-cycle-info | awk '{print $2}') - version="$current_date.$release_cycle.$release_cycle_counter" + version="$release_year.$release_month.$release_cycle.$release_cycle_counter" echo "PACKAGE_VERSION=$version" >> $GITHUB_ENV - name: package release artifacts diff --git a/Justfile b/Justfile index d52041e73f..8e260b9804 100644 --- a/Justfile +++ b/Justfile @@ -374,10 +374,11 @@ package-arch arch: if [[ -n $PACKAGE_VERSION ]]; then version="$PACKAGE_VERSION" else - current_date=$(date +%Y.%m) + release_year=$(grep 'release-year:' release-cycle-info | awk '{print $2}') + release_month=$(grep 'release-month:' release-cycle-info | awk '{print $2}') release_cycle=$(grep 'release-cycle:' release-cycle-info | awk '{print $2}') release_cycle_counter=$(grep 'release-cycle-counter:' release-cycle-info | awk '{print $2}') - version="$current_date.$release_cycle.$release_cycle_counter" + version="$release_year.$release_month.$release_cycle.$release_cycle_counter" fi architecture="{{arch}}" zip_filename="${version}.autonomi.${architecture}.zip" diff --git a/release-cycle-info b/release-cycle-info index 14b23f7ad5..f86d2490ca 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -1,3 +1,9 @@ +# The reason for having the year and month here rather than reading it from the OS is because we +# have two cycles per month, but the RC can be built for the first cycle of the following month, in +# the current month. So for example, you could build the first September RC before the month of +# August ends, hence reading the current date from the OS would give you 08 rather than 09. The same +# thing applies to the year. So, it's simple enough to just define them here. +# # The release-cycle is the cycle within the current month. It will be 1 or 2. It is set at the # beginning of the cycle. # @@ -6,5 +12,7 @@ # # Both of these numbers are used in the packaged version number, which is a collective version # number for all the released binaries. +release-year: 2024 +release-month: 09 release-cycle: 1 release-cycle-counter: 1 From 92c6c4ab1c738ed7767c5ae89b86c225e1c38ef7 Mon Sep 17 00:00:00 2001 From: Roland Sherwin Date: Tue, 27 Aug 2024 20:21:20 +0530 Subject: [PATCH 03/35] Revert "chore(metrics): add unit to certain metrics" This reverts commit 0bc6074dc1db9081bb2a0561a30152f180ace958. --- sn_networking/src/metrics/mod.rs | 8 +++----- sn_node/src/metrics.rs | 11 ++++------- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/sn_networking/src/metrics/mod.rs b/sn_networking/src/metrics/mod.rs index bd56c0b0c9..a7fdfbeee1 100644 --- a/sn_networking/src/metrics/mod.rs +++ b/sn_networking/src/metrics/mod.rs @@ -12,7 +12,7 @@ use libp2p::metrics::{Metrics as Libp2pMetrics, Recorder}; use prometheus_client::metrics::family::Family; use prometheus_client::{ metrics::{counter::Counter, gauge::Gauge}, - registry::{Registry, Unit}, + registry::Registry, }; use sysinfo::{Pid, ProcessRefreshKind, System}; use tokio::time::Duration; @@ -118,18 +118,16 @@ impl NetworkMetricsRecorder { ); let process_memory_used_mb = Gauge::default(); - sub_registry.register_with_unit( + sub_registry.register( "process_memory_used_mb", "Memory used by the process in MegaBytes", - Unit::Other("MegaByte".to_string()), process_memory_used_mb.clone(), ); let process_cpu_usage_percentage = Gauge::default(); - sub_registry.register_with_unit( + sub_registry.register( "process_cpu_usage_percentage", "The percentage of CPU used by the process. Value is from 0-100", - Unit::Other("Percentage".to_string()), process_cpu_usage_percentage.clone(), ); diff --git a/sn_node/src/metrics.rs b/sn_node/src/metrics.rs index 4e64d4a771..4ba458448e 100644 --- a/sn_node/src/metrics.rs +++ b/sn_node/src/metrics.rs @@ -15,7 +15,7 @@ use prometheus_client::{ gauge::Gauge, histogram::{exponential_buckets, Histogram}, }, - registry::{Registry, Unit}, + registry::Registry, }; use sn_networking::Instant; @@ -102,26 +102,23 @@ impl NodeMetricsRecorder { ); let current_reward_wallet_balance = Gauge::default(); - sub_registry.register_with_unit( + sub_registry.register( "current_reward_wallet_balance", "The number of Nanos in the node reward wallet", - Unit::Other("Nano".to_string()), current_reward_wallet_balance.clone(), ); let total_forwarded_rewards = Gauge::default(); - sub_registry.register_with_unit( + sub_registry.register( "total_forwarded_rewards", "The cumulative number of Nanos forwarded by the node", - Unit::Other("Nano".to_string()), total_forwarded_rewards.clone(), ); let uptime = Gauge::default(); - sub_registry.register_with_unit( + sub_registry.register( "uptime", "The uptime of the node in seconds", - Unit::Seconds, uptime.clone(), ); From d341310eb8b262a3a240ff31799d6a40b3b8dfa4 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 2 Sep 2024 11:04:52 +0200 Subject: [PATCH 04/35] fix(launchpad): storage mountpoint not set plus tests --- Cargo.lock | 552 ++++++++++++++++------------- node-launchpad/Cargo.toml | 3 + node-launchpad/src/app.rs | 274 ++++++++++++-- node-launchpad/src/bin/tui/main.rs | 1 + node-launchpad/src/config.rs | 172 ++++++++- node-launchpad/src/system.rs | 14 +- 6 files changed, 722 insertions(+), 294 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2643369385..9d4a76fc4b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "adler2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" + [[package]] name = "aead" version = "0.5.2" @@ -225,9 +231,9 @@ checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -237,9 +243,9 @@ checksum = "d92bec98840b8f03a5ff5413de5293bfcd8bf96467cf5452609f939ec6f5de16" [[package]] name = "asn1-rs" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ad1373757efa0f70ec53939aabc7152e1591cb485208052993070ac8d2429d" +checksum = "5493c3bedbacf7fd7382c6346bbd66687d12bbaad3a89a2d2c303ee6cf20b048" dependencies = [ "asn1-rs-derive", "asn1-rs-impl", @@ -253,13 +259,13 @@ dependencies = [ [[package]] name = "asn1-rs-derive" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1" +checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", "synstructure 0.13.1", ] @@ -271,18 +277,19 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] name = "assert_cmd" -version = "2.0.15" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc65048dd435533bb1baf2ed9956b9a278fbfdcf90301b39ee117f06c0199d37" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" dependencies = [ "anstyle", "bstr", "doc-comment", + "libc", "predicates 3.1.2", "predicates-core", "predicates-tree", @@ -312,9 +319,9 @@ checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" [[package]] name = "async-io" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +checksum = "444b0228950ee6501b3568d3c93bf1176a1fdbc3b758dcd9475046d30f4dc7e8" dependencies = [ "async-lock", "cfg-if", @@ -326,7 +333,7 @@ dependencies = [ "rustix", "slab", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -359,18 +366,18 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -505,7 +512,7 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.7.4", "object", "rustc-demangle", ] @@ -845,9 +852,9 @@ checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" [[package]] name = "bytemuck" -version = "1.16.1" +version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" +checksum = "773d90827bc3feecfb67fab12e24de0749aad83c74b9504ecde46237b5cd24e2" [[package]] name = "byteorder" @@ -857,9 +864,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.6.1" +version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952" +checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" dependencies = [ "serde", ] @@ -887,9 +894,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ec6b951b160caa93cc0c7b209e5a3bff7aae9062213451ac99493cd844c239" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -949,21 +956,22 @@ dependencies = [ [[package]] name = "cbor4ii" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b4c883b9cc4757b061600d39001d4d0232bece4a3174696cf8f58a14db107d" +checksum = "472931dd4dfcc785075b09be910147f9c6258883fc4591d0dac6116392b2daa6" dependencies = [ "serde", ] [[package]] name = "cc" -version = "1.1.7" +version = "1.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26a5c3fd7bfa1ce3897a3a3501d362b2d87b7f2583ebcb4a949ec25911025cbc" +checksum = "57b6a275aa2903740dc87da01c62040406b8812552e97129a63ea8850a17c6e6" dependencies = [ "jobserver", "libc", + "shlex", ] [[package]] @@ -1065,9 +1073,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.11" +version = "4.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" +checksum = "ed6719fffa43d0d87e5fd8caeab59be1554fb028cd30edc88fc4369b17971019" dependencies = [ "clap_builder", "clap_derive", @@ -1085,9 +1093,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.11" +version = "4.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" +checksum = "216aec2b177652e3846684cbfe25c9964d18ec45234f0f5da5157b207ed1aab6" dependencies = [ "anstream", "anstyle", @@ -1100,14 +1108,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.11" +version = "4.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" +checksum = "501d359d5f3dcaf6ecdeee48833ae73ec6e42723a1e52419c79abf9507eec0a0" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1293,9 +1301,9 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "core2" @@ -1308,18 +1316,18 @@ dependencies = [ [[package]] name = "cpp_demangle" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +checksum = "96e58d342ad113c2b878f16d5d034c03be492ae460cdbc02b7f0f2284d310c7d" dependencies = [ "cfg-if", ] [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "51e852e6dc9a5bed1fae92dd2375037bf2b768725bf3be87811edee3249d09ad" dependencies = [ "libc", ] @@ -1527,7 +1535,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1549,7 +1557,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", "synstructure 0.13.1", ] @@ -1574,7 +1582,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1585,7 +1593,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1801,7 +1809,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -1848,9 +1856,9 @@ checksum = "dcbb2bf8e87535c23f7a8a321e364ce21462d0ff10cb6407820e8e96dfff6653" [[package]] name = "dunce" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" +checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "ecdsa" @@ -1939,7 +1947,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -2038,9 +2046,9 @@ checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" [[package]] name = "fastrand" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" [[package]] name = "ff" @@ -2097,14 +2105,14 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -2127,12 +2135,12 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" +checksum = "324a1be68054ef05ad64b861cc9eaf1d623d2d8cb25b4bf2cb9cdd902b4bf253" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.8.0", ] [[package]] @@ -2270,7 +2278,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -2505,9 +2513,9 @@ dependencies = [ [[package]] name = "gix-config-value" -version = "0.14.7" +version = "0.14.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b328997d74dd15dc71b2773b162cb4af9a25c424105e4876e6d0686ab41c383e" +checksum = "03f76169faa0dec598eac60f83d7fcdd739ec16596eca8fb144c88973dbe6f8c" dependencies = [ "bitflags 2.6.0", "bstr", @@ -2577,9 +2585,9 @@ dependencies = [ [[package]] name = "gix-fs" -version = "0.11.2" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6adf99c27cdf17b1c4d77680c917e0d94d8783d4e1c73d3be0d1d63107163d7a" +checksum = "f2bfe6249cfea6d0c0e0990d5226a4cb36f030444ba9e35e0639275db8f98575" dependencies = [ "fastrand", "gix-features", @@ -2588,9 +2596,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.16.4" +version = "0.16.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7df15afa265cc8abe92813cd354d522f1ac06b29ec6dfa163ad320575cb447" +checksum = "74908b4bbc0a0a40852737e5d7889f676f081e340d5451a16e5b4c50d592f111" dependencies = [ "bitflags 2.6.0", "bstr", @@ -2666,7 +2674,7 @@ checksum = "999ce923619f88194171a67fb3e6d613653b8d4d6078b529b15a765da0edcc17" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -2728,9 +2736,9 @@ dependencies = [ [[package]] name = "gix-path" -version = "0.10.9" +version = "0.10.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d23d5bbda31344d8abc8de7c075b3cf26e5873feba7c4a15d916bce67382bd9" +checksum = "38d5b8722112fa2fa87135298780bc833b0e9f6c56cc82795d209804b3a03484" dependencies = [ "bstr", "gix-trace", @@ -2819,9 +2827,9 @@ dependencies = [ [[package]] name = "gix-sec" -version = "0.10.7" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1547d26fa5693a7f34f05b4a3b59a90890972922172653bcb891ab3f09f436df" +checksum = "0fe4d52f30a737bbece5276fab5d3a8b276dc2650df963e293d0673be34e7a5f" dependencies = [ "bitflags 2.6.0", "gix-path", @@ -2831,9 +2839,9 @@ dependencies = [ [[package]] name = "gix-tempfile" -version = "14.0.1" +version = "14.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "006acf5a613e0b5cf095d8e4b3f48c12a60d9062aa2b2dd105afaf8344a5600c" +checksum = "046b4927969fa816a150a0cda2e62c80016fe11fb3c3184e4dddf4e542f108aa" dependencies = [ "gix-fs", "libc", @@ -2869,9 +2877,9 @@ dependencies = [ [[package]] name = "gix-url" -version = "0.27.4" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2eb9b35bba92ea8f0b5ab406fad3cf6b87f7929aa677ff10aa042c6da621156" +checksum = "fd280c5e84fb22e128ed2a053a0daeacb6379469be6a85e3d518a0636e160c89" dependencies = [ "bstr", "gix-features", @@ -2984,7 +2992,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.2.6", + "indexmap 2.5.0", "slab", "tokio", "tokio-util 0.7.11", @@ -3372,7 +3380,7 @@ dependencies = [ "tokio", "tokio-rustls 0.26.0", "tower-service", - "webpki-roots 0.26.3", + "webpki-roots 0.26.5", ] [[package]] @@ -3389,9 +3397,9 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab92f4f49ee4fb4f997c784b7a2e0fa70050211e0b6a287f898c3c9785ca956" +checksum = "cde7055719c54e36e95e8719f95883f22072a48ede39db7fc17a4e1d5281e9b9" dependencies = [ "bytes", "futures-channel", @@ -3538,9 +3546,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.6" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -3562,12 +3570,12 @@ dependencies = [ [[package]] name = "inferno" -version = "0.11.20" +version = "0.11.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c77a3ae7d4761b9c64d2c030f70746ceb8cfba32dce0325a56792e0a4816c31" +checksum = "232929e1d75fe899576a3d5c7416ad0d88dbfbb3c3d6aa00873a7408a50ddb88" dependencies = [ "ahash", - "indexmap 2.2.6", + "indexmap 2.5.0", "is-terminal", "itoa", "log", @@ -3631,7 +3639,7 @@ dependencies = [ "socket2", "widestring", "windows-sys 0.48.0", - "winreg 0.50.0", + "winreg", ] [[package]] @@ -3642,11 +3650,11 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "is-terminal" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" +checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" dependencies = [ - "hermit-abi 0.3.9", + "hermit-abi 0.4.0", "libc", "windows-sys 0.52.0", ] @@ -3701,9 +3709,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" dependencies = [ "wasm-bindgen", ] @@ -3736,9 +3744,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.158" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" [[package]] name = "libm" @@ -4146,7 +4154,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -4224,9 +4232,9 @@ dependencies = [ [[package]] name = "libp2p-websocket-websys" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d6f6c7ad3960dc9da18bead8468fc2dce9992d23d84557fd2345c86a992d70d" +checksum = "f95cd8a32fcf94ad1e5c2de37c2a05a5a4188d8358b005859a0fc9e63b6953bc" dependencies = [ "bytes", "futures", @@ -4242,9 +4250,9 @@ dependencies = [ [[package]] name = "libp2p-yamux" -version = "0.45.1" +version = "0.45.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200cbe50349a44760927d50b431d77bed79b9c0a3959de1af8d24a63434b71e5" +checksum = "ddd5265f6b80f94d48a3963541aad183cc598a645755d2f1805a373e41e0716b" dependencies = [ "either", "futures", @@ -4263,6 +4271,7 @@ checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ "bitflags 2.6.0", "libc", + "redox_syscall", ] [[package]] @@ -4295,9 +4304,9 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" +checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" dependencies = [ "hashbrown 0.14.5", ] @@ -4387,6 +4396,15 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +dependencies = [ + "adler2", +] + [[package]] name = "minreq" version = "2.12.0" @@ -4414,9 +4432,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4569e456d394deccd22ce1c1913e6ea0e54519f577285001215d33557431afe4" +checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" dependencies = [ "hermit-abi 0.3.9", "libc", @@ -4475,7 +4493,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -4697,7 +4715,7 @@ dependencies = [ "pretty_assertions", "prometheus-parse", "ratatui", - "reqwest 0.12.5", + "reqwest 0.12.7", "serde", "serde_json", "signal-hook", @@ -4708,6 +4726,7 @@ dependencies = [ "strip-ansi-escapes", "strum", "sysinfo", + "tempfile", "tokio", "tokio-util 0.7.11", "tracing", @@ -4715,7 +4734,7 @@ dependencies = [ "tracing-subscriber", "tui-input", "vergen", - "which 6.0.1", + "which 6.0.3", ] [[package]] @@ -4899,9 +4918,9 @@ dependencies = [ [[package]] name = "oid-registry" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c958dd45046245b9c3c2547369bb634eb461670b2e7e0de552905801a648d1d" +checksum = "a8d8034d9489cdaf79228eb9f6a3b8d7bb32ba00d6645ebd48eef4077ceb5bd9" dependencies = [ "asn1-rs", ] @@ -5126,7 +5145,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -5213,7 +5232,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -5234,7 +5253,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.2.6", + "indexmap 2.5.0", "serde", "serde_derive", ] @@ -5256,7 +5275,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -5304,7 +5323,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.2.6", + "indexmap 2.5.0", "quick-xml 0.32.0", "serde", "time", @@ -5340,9 +5359,9 @@ dependencies = [ [[package]] name = "polling" -version = "3.7.2" +version = "3.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3ed00ed3fbf728b5816498ecd316d1716eecaced9c0c8d2c5a6740ca214985b" +checksum = "cc2790cd301dec6cd3b7a025e4815cf825724a51c98dccfe6a3e55f05ffb6511" dependencies = [ "cfg-if", "concurrent-queue", @@ -5350,7 +5369,7 @@ dependencies = [ "pin-project-lite", "rustix", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -5411,9 +5430,12 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" +dependencies = [ + "zerocopy", +] [[package]] name = "predicates" @@ -5528,7 +5550,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -5711,9 +5733,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.2" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4ceeeeabace7857413798eb1ffa1e9c905a9946a57d81fb69b4b71c4d8eb3ad" +checksum = "a2d2fb862b7ba45e615c1429def928f2e15f815bdf933b27a2d3824e224c1f46" dependencies = [ "bytes", "futures-io", @@ -5722,6 +5744,7 @@ dependencies = [ "quinn-udp", "rustc-hash", "rustls 0.23.12", + "socket2", "thiserror", "tokio", "tracing", @@ -5729,9 +5752,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.3" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddf517c03a109db8100448a4be38d498df8a210a99fe0e1b9eaf39e78c640efe" +checksum = "ea0a9b3a42929fad8a7c3de7f86ce0814cfa893328157672680e9fb1145549c5" dependencies = [ "bytes", "rand 0.8.5", @@ -5753,14 +5776,15 @@ dependencies = [ "libc", "once_cell", "socket2", + "tracing", "windows-sys 0.52.0", ] [[package]] name = "quote" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] @@ -6041,15 +6065,6 @@ dependencies = [ "rand_core 0.3.1", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.3" @@ -6061,9 +6076,9 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" +checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", @@ -6072,9 +6087,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.5" +version = "1.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" dependencies = [ "aho-corasick", "memchr", @@ -6152,14 +6167,14 @@ dependencies = [ "wasm-bindgen-futures", "web-sys", "webpki-roots 0.25.4", - "winreg 0.50.0", + "winreg", ] [[package]] name = "reqwest" -version = "0.12.5" +version = "0.12.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d6d2a27d57148378eb5e111173f4276ad26340ecc5c49a4a2152167a2d6a37" +checksum = "f8f4955649ef5c38cc7f9e8aa41761d48fb9677197daea9984dc54f56aad5e63" dependencies = [ "base64 0.22.1", "bytes", @@ -6180,7 +6195,7 @@ dependencies = [ "pin-project-lite", "quinn", "rustls 0.23.12", - "rustls-pemfile 2.1.2", + "rustls-pemfile 2.1.3", "rustls-pki-types", "serde", "serde_json", @@ -6193,8 +6208,8 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.26.3", - "winreg 0.52.0", + "webpki-roots 0.26.5", + "windows-registry", ] [[package]] @@ -6220,9 +6235,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.45" +version = "0.8.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade4539f42266ded9e755c605bdddf546242b2c961b03b06a7375260788a0523" +checksum = "57397d16646700483b67d2dd6511d79318f9d057fdbd21a4066aeac8b41d310a" dependencies = [ "bytemuck", ] @@ -6345,15 +6360,15 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "583034fd73374156e66797ed8e5b0d5690409c9226b22d87cb7f19821c05d152" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -6369,9 +6384,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ "bitflags 2.6.0", "errno", @@ -6426,7 +6441,7 @@ dependencies = [ "once_cell", "ring 0.17.8", "rustls-pki-types", - "rustls-webpki 0.102.6", + "rustls-webpki 0.102.7", "subtle", "zeroize", ] @@ -6451,9 +6466,9 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29993a25686778eb88d4189742cd713c9bce943bc54251a33509dc63cbacf73d" +checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" dependencies = [ "base64 0.22.1", "rustls-pki-types", @@ -6461,9 +6476,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "976295e77ce332211c0d24d92c0e83e50f5c5f046d11082cea19f3df13a3562d" +checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" [[package]] name = "rustls-webpki" @@ -6477,9 +6492,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.102.6" +version = "0.102.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6b52d4fda176fd835fdc55a835d4a89b8499cad995885a21149d5ad62f852e" +checksum = "84678086bd54edf2b415183ed7a94d0efb049f1b646a33e22a36f3794be6ae56" dependencies = [ "ring 0.17.8", "rustls-pki-types", @@ -6673,9 +6688,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +checksum = "99fce0ffe7310761ca6bf9faf5115afbc19688edd00171d81b1bb1b116c63e09" dependencies = [ "serde_derive", ] @@ -6691,20 +6706,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.204" +version = "1.0.209" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] name = "serde_json" -version = "1.0.121" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +checksum = "8043c06d9f82bd7271361ed64f415fe5e12a77fdb52e573e7f06a516dea329ad" dependencies = [ "itoa", "memchr", @@ -6723,9 +6738,9 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.176" +version = "1.0.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a2f49ace1498612d14f7e0b8245519584db8299541dfe31a06374a828d620ab" +checksum = "7f901ee573cab6b3060453d2d5f0bae4e6d628c23c0a962ff9b5f1d7c8d4f1ed" dependencies = [ "serde", ] @@ -6748,7 +6763,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "itoa", "ryu", "serde", @@ -6848,6 +6863,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "signal-hook" version = "0.3.17" @@ -6939,7 +6960,7 @@ dependencies = [ "predicates 3.1.2", "prost 0.9.0", "rand 0.8.5", - "reqwest 0.12.5", + "reqwest 0.12.7", "semver", "serde", "serde_json", @@ -6957,21 +6978,21 @@ dependencies = [ "tracing", "users", "uuid", - "which 6.0.1", + "which 6.0.3", ] [[package]] name = "sn-releases" -version = "0.2.6" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9160dd891b488e9a41b8e8a481a3f39648d58a94a19b177af863d93c7fc52a54" +checksum = "7519b2daa6a6241938a17c034064ac38f5367355abc81cae55abf16854b0e9e4" dependencies = [ "async-trait", "chrono", "flate2", "lazy_static", "regex", - "reqwest 0.12.5", + "reqwest 0.12.7", "semver", "serde_json", "tar", @@ -7045,7 +7066,7 @@ dependencies = [ "libp2p", "rand 0.8.5", "rayon", - "reqwest 0.12.5", + "reqwest 0.12.7", "rmp-serde", "rpassword", "serde", @@ -7162,7 +7183,7 @@ dependencies = [ "hex 0.4.3", "indicatif", "minreq", - "reqwest 0.12.5", + "reqwest 0.12.7", "serde", "serde_json", "sn_build_info", @@ -7285,7 +7306,7 @@ dependencies = [ "prost 0.9.0", "rand 0.8.5", "rayon", - "reqwest 0.12.5", + "reqwest 0.12.7", "rmp-serde", "self_encryption", "serde", @@ -7349,7 +7370,7 @@ dependencies = [ "lazy_static", "libp2p", "rand 0.8.5", - "reqwest 0.12.5", + "reqwest 0.12.7", "sn_protocol", "thiserror", "tokio", @@ -7543,7 +7564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d904e7009df136af5297832a3ace3370cd14ff1546a232f4f185036c2736fcac" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -7598,7 +7619,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -7609,9 +7630,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic-common" -version = "12.10.0" +version = "12.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16629323a4ec5268ad23a575110a724ad4544aae623451de600c747bf87b36cf" +checksum = "b1944ea8afd197111bca0c0edea1e1f56abb3edd030e240c1035cc0e3ff51fec" dependencies = [ "debugid", "memmap2", @@ -7621,9 +7642,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.10.0" +version = "12.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c043a45f08f41187414592b3ceb53fb0687da57209cc77401767fb69d5b596" +checksum = "ddaccaf1bf8e73c4f64f78dbb30aadd6965c71faa4ff3fba33f8d7296cf94a87" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -7643,9 +7664,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.72" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -7663,6 +7684,9 @@ name = "sync_wrapper" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +dependencies = [ + "futures-core", +] [[package]] name = "synstructure" @@ -7684,7 +7708,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -7742,14 +7766,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.10.1" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" dependencies = [ "cfg-if", "fastrand", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7796,7 +7821,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -7914,14 +7939,14 @@ dependencies = [ [[package]] name = "tokio" -version = "1.39.2" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "daa4fb1bc778bd6f04cbfc4bb2d06a7396a8f299dc33ea1900cedaa316f467b1" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes", "libc", - "mio 1.0.1", + "mio 1.0.2", "parking_lot", "pin-project-lite", "signal-hook-registry", @@ -7948,7 +7973,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -8035,9 +8060,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81967dd0dd2c1ab0bc3468bd7caecc32b8a4aa47d0c8c695d8c2b2108168d62c" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -8047,20 +8072,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.7" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fb9f64314842840f1d940ac544da178732128f1c78c21772e876579e0da1db" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.22.17" +version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9f8729f5aea9562aac1cc0441f5d6de3cff1ee0c5d67293eeca5eb36ee7c16" +checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.2.6", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", @@ -8161,15 +8186,15 @@ dependencies = [ [[package]] name = "tower-layer" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" @@ -8203,7 +8228,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -8323,7 +8348,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568" dependencies = [ "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -8463,9 +8488,9 @@ checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" [[package]] name = "universal-hash" @@ -8683,34 +8708,35 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" +checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" dependencies = [ "cfg-if", "js-sys", @@ -8720,9 +8746,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8730,22 +8756,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.93" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" [[package]] name = "wasmtimer" @@ -8763,9 +8789,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.70" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" dependencies = [ "js-sys", "wasm-bindgen", @@ -8809,9 +8835,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] @@ -8830,9 +8856,9 @@ dependencies = [ [[package]] name = "which" -version = "6.0.1" +version = "6.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7" +checksum = "b4ee928febd44d98f2f459a4a79bd4d928591333a494a10a868418ac1b39cf1f" dependencies = [ "either", "home", @@ -8864,11 +8890,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -8915,6 +8941,36 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-registry" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" +dependencies = [ + "windows-result", + "windows-strings", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result", + "windows-targets 0.52.6", +] + [[package]] name = "windows-sys" version = "0.48.0" @@ -8933,6 +8989,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -9056,9 +9121,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.16" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b480ae9340fc261e6be3e95a1ba86d54ae3f9171132a73ce8d4bbaf68339507c" +checksum = "68a9bda4691f099d435ad181000724da8e5899daa10713c2d432552b9ccd3a6f" dependencies = [ "memchr", ] @@ -9073,16 +9138,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "winreg" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a277a57398d4bfa075df44f501a17cfdf8542d224f0d36095a2adc7aee4ef0a5" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] - [[package]] name = "winsafe" version = "0.0.19" @@ -9140,9 +9195,9 @@ dependencies = [ [[package]] name = "xml-rs" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "791978798f0597cfc70478424c2b4fdc2b7a8024aaff78497ef00f24ef674193" +checksum = "539a77ee7c0de333dcc6da69b177380a0b81e0dacfa4f7344c465a36871ee601" [[package]] name = "xmltree" @@ -9228,6 +9283,7 @@ version = "0.7.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ + "byteorder", "zerocopy-derive", ] @@ -9239,7 +9295,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -9259,7 +9315,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.72", + "syn 2.0.77", ] [[package]] @@ -9303,9 +9359,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.12+zstd.1.5.6" +version = "2.0.13+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e40c320c3cb459d9a9ff6de98cff88f4751ee9275d140e2be94a2b74e4c13" +checksum = "38ff0f21cfee8f97d94cef41359e0c89aa6113028ab0291aa8ca0038995a95aa" dependencies = [ "cc", "pkg-config", diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 1da1f8e366..13f6803967 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -67,3 +67,6 @@ faccess = "0.2.4" [build-dependencies] vergen = { version = "8.2.6", features = ["build", "git", "gitoxide", "cargo"] } + +[dev-dependencies] +tempfile = "3.12.0" diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index 48804d6c79..09053998fd 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -23,9 +23,10 @@ use crate::{ config::{get_launchpad_nodes_data_dir_path, AppData, Config}, mode::{InputMode, Scene}, style::SPACE_CADET, + system::{get_default_mount_point, get_primary_mount_point, get_primary_mount_point_name}, tui, }; -use color_eyre::eyre::{eyre, Result}; +use color_eyre::eyre::Result; use crossterm::event::KeyEvent; use ratatui::{prelude::Rect, style::Style, widgets::Block}; use sn_peers_acquisition::PeersArgs; @@ -50,17 +51,35 @@ impl App { frame_rate: f64, peers_args: PeersArgs, safenode_path: Option, + app_data_path: Option, ) -> Result { // Configurations - let app_data = AppData::load()?; + let app_data = AppData::load(app_data_path)?; let config = Config::new()?; + // Tries to set the data dir path based on the storage mountpoint set by the user, + // if not set, it tries to get the default mount point (where the executable is) and + // create the nodes data dir there. + // If even that fails, it will create the nodes data dir in the primary mount point. let data_dir_path = match &app_data.storage_mountpoint { Some(path) => get_launchpad_nodes_data_dir_path(&PathBuf::from(path), true)?, - None => return Err(eyre!("Storage mountpoint for node data is not set")), + None => match get_default_mount_point() { + Ok((_, path)) => get_launchpad_nodes_data_dir_path(&path, true)?, + Err(_) => get_launchpad_nodes_data_dir_path(&get_primary_mount_point(), true)?, + }, }; debug!("Data dir path for nodes: {data_dir_path:?}"); + // App data validations + let storage_mountpoint = app_data + .storage_mountpoint + .clone() + .unwrap_or(get_primary_mount_point()); + let storage_drive = app_data + .storage_drive + .clone() + .unwrap_or(get_primary_mount_point_name()?); + // Main Screens let status = Status::new( app_data.nodes_to_start, @@ -71,14 +90,8 @@ impl App { ) .await?; let options = Options::new( - app_data - .storage_mountpoint - .clone() - .ok_or_else(|| eyre!("Creating Options screen, storage_mountpoint is None"))?, - app_data - .storage_drive - .clone() - .ok_or_else(|| eyre!("Creating Options screen, storage_drive is None"))?, + storage_mountpoint.clone(), + storage_drive.clone(), app_data.discord_username.clone(), ) .await?; @@ -87,17 +100,8 @@ impl App { // Popups let reset_nodes = ResetNodesPopup::default(); let discord_username_input = BetaProgramme::new(app_data.discord_username.clone()); - let manage_nodes = ManageNodes::new( - app_data.nodes_to_start, - app_data - .storage_mountpoint - .clone() - .ok_or_else(|| eyre!("Creating Manage Nodes screen, storage_drive is None"))?, - )?; - let change_drive = - ChangeDrivePopup::new(app_data.storage_mountpoint.clone().ok_or_else(|| { - eyre!("Creating Change Drive screen, storage_mountpoint is None") - })?)?; + let manage_nodes = ManageNodes::new(app_data.nodes_to_start, storage_mountpoint.clone())?; + let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; Ok(Self { config, @@ -217,7 +221,7 @@ impl App { })?; } Action::SwitchScene(scene) => { - info!("Scene swtiched to: {scene:?}"); + info!("Scene switched to: {scene:?}"); self.scene = scene; } Action::SwitchInputMode(mode) => { @@ -228,18 +232,18 @@ impl App { Action::StoreDiscordUserName(ref username) => { debug!("Storing discord username: {username:?}"); self.app_data.discord_username.clone_from(username); - self.app_data.save()?; + self.app_data.save(None)?; } Action::StoreNodesToStart(count) => { debug!("Storing nodes to start: {count:?}"); self.app_data.nodes_to_start = count; - self.app_data.save()?; + self.app_data.save(None)?; } Action::StoreStorageDrive(ref drive_mountpoint, ref drive_name) => { debug!("Storing storage drive: {drive_mountpoint:?}, {drive_name:?}"); self.app_data.storage_mountpoint = Some(drive_mountpoint.clone()); self.app_data.storage_drive = Some(drive_name.as_str().to_string()); - self.app_data.save()?; + self.app_data.save(None)?; } _ => {} } @@ -266,3 +270,221 @@ impl App { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use color_eyre::eyre::Result; + use sn_peers_acquisition::PeersArgs; + use std::io::Cursor; + use std::io::Write; + use tempfile::tempdir; + + #[tokio::test] + async fn test_app_creation_with_valid_config() -> Result<()> { + // Create a temporary directory for our test + let temp_dir = tempdir()?; + let config_path = temp_dir.path().join("valid_config.json"); + + let mountpoint = get_primary_mount_point(); + + // Create a valid configuration file + let valid_config = format!( + r#" + {{ + "discord_username": "happy_user", + "nodes_to_start": 5, + "storage_mountpoint": "{}", + "storage_drive": "C:" + }} + "#, + mountpoint.display() + ); + + std::fs::write(&config_path, valid_config)?; + + // Create default PeersArgs + let peers_args = PeersArgs::default(); + + // Create a buffer to capture output + let mut output = Cursor::new(Vec::new()); + + // Create and run the App, capturing its output + let app_result = App::new(60.0, 60.0, peers_args, None, Some(config_path)).await; + + match app_result { + Ok(app) => { + // Check if the discord_username and nodes_to_start were correctly loaded + assert_eq!(app.app_data.discord_username, "happy_user"); + assert_eq!(app.app_data.nodes_to_start, 5); + // Check if the storage_mountpoint is set correctly + assert_eq!(app.app_data.storage_mountpoint, Some(mountpoint)); + // Check if the storage_drive is set correctly + assert_eq!(app.app_data.storage_drive, Some("C:".to_string())); + + write!(output, "App created successfully with valid configuration")?; + } + Err(e) => { + write!(output, "App creation failed: {}", e)?; + } + } + + // Convert captured output to string + let output_str = String::from_utf8(output.into_inner())?; + + // Check if the success message is in the output + assert!( + output_str.contains("App created successfully with valid configuration"), + "Unexpected output: {}", + output_str + ); + + Ok(()) + } + + #[tokio::test] + async fn test_app_should_run_when_storage_mountpoint_not_set() -> Result<()> { + // Create a temporary directory for our test + let temp_dir = tempdir()?; + let test_app_data_path = temp_dir.path().join("test_app_data.json"); + + // Create a custom configuration file with only the first two settings + let custom_config = r#" + { + "discord_username": "test_user", + "nodes_to_start": 3 + } + "#; + std::fs::write(&test_app_data_path, custom_config)?; + + // Create default PeersArgs + let peers_args = PeersArgs::default(); + + // Create a buffer to capture output + let mut output = Cursor::new(Vec::new()); + + // Create and run the App, capturing its output + let app_result = App::new(60.0, 60.0, peers_args, None, Some(test_app_data_path)).await; + + match app_result { + Ok(app) => { + // Check if the discord_username and nodes_to_start were correctly loaded + assert_eq!(app.app_data.discord_username, "test_user"); + assert_eq!(app.app_data.nodes_to_start, 3); + // Check if the storage_mountpoint is None (not set) + assert_eq!(app.app_data.storage_mountpoint, None); + // Check if the storage_drive is None (not set) + assert_eq!(app.app_data.storage_drive, None); + + write!( + output, + "App created successfully with partial configuration" + )?; + } + Err(e) => { + write!(output, "App creation failed: {}", e)?; + } + } + + // Convert captured output to string + let output_str = String::from_utf8(output.into_inner())?; + + // Check if the success message is in the output + assert!( + output_str.contains("App created successfully with partial configuration"), + "Unexpected output: {}", + output_str + ); + + Ok(()) + } + + #[tokio::test] + async fn test_app_creation_when_config_file_doesnt_exist() -> Result<()> { + // Create a temporary directory for our test + let temp_dir = tempdir()?; + let non_existent_config_path = temp_dir.path().join("non_existent_config.json"); + + // Create default PeersArgs + let peers_args = PeersArgs::default(); + + // Create a buffer to capture output + let mut output = Cursor::new(Vec::new()); + + // Create and run the App, capturing its output + let app_result = + App::new(60.0, 60.0, peers_args, None, Some(non_existent_config_path)).await; + + match app_result { + Ok(app) => { + assert_eq!(app.app_data.discord_username, ""); + assert_eq!(app.app_data.nodes_to_start, 1); + assert_eq!(app.app_data.storage_mountpoint, None); + assert_eq!(app.app_data.storage_drive, None); + + write!( + output, + "App created successfully with default configuration" + )?; + } + Err(e) => { + write!(output, "App creation failed: {}", e)?; + } + } + + // Convert captured output to string + let output_str = String::from_utf8(output.into_inner())?; + + // Check if the success message is in the output + assert!( + output_str.contains("App created successfully with default configuration"), + "Unexpected output: {}", + output_str + ); + + Ok(()) + } + + #[tokio::test] + async fn test_app_creation_with_invalid_storage_mountpoint() -> Result<()> { + // Create a temporary directory for our test + let temp_dir = tempdir()?; + let config_path = temp_dir.path().join("invalid_config.json"); + + // Create a configuration file with an invalid storage_mountpoint + let invalid_config = r#" + { + "discord_username": "test_user", + "nodes_to_start": 5, + "storage_mountpoint": "/non/existent/path", + "storage_drive": "Z:" + } + "#; + std::fs::write(&config_path, invalid_config)?; + + // Create default PeersArgs + let peers_args = PeersArgs::default(); + + // Create and run the App, capturing its output + let app_result = App::new(60.0, 60.0, peers_args, None, Some(config_path)).await; + + // Could be that the mountpoint doesn't exists + // or that the user doesn't have permissions to access it + match app_result { + Ok(_) => { + panic!("App creation should have failed due to invalid storage_mountpoint"); + } + Err(e) => { + assert!( + e.to_string().contains( + "Cannot find the primary disk. Configuration file might be wrong." + ) || e.to_string().contains("Failed to create nodes data dir in"), + "Unexpected error message: {}", + e + ); + } + } + + Ok(()) + } +} diff --git a/node-launchpad/src/bin/tui/main.rs b/node-launchpad/src/bin/tui/main.rs index 965eefb142..2ceb235900 100644 --- a/node-launchpad/src/bin/tui/main.rs +++ b/node-launchpad/src/bin/tui/main.rs @@ -65,6 +65,7 @@ async fn tokio_main() -> Result<()> { args.frame_rate, args.peers, args.safenode_path, + None, ) .await?; app.run().await?; diff --git a/node-launchpad/src/config.rs b/node-launchpad/src/config.rs index b2f192324f..3db61eb518 100644 --- a/node-launchpad/src/config.rs +++ b/node-launchpad/src/config.rs @@ -6,7 +6,6 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. -use crate::system; use crate::system::get_primary_mount_point; use crate::{action::Action, mode::Scene}; use color_eyre::eyre::{eyre, Result}; @@ -98,7 +97,7 @@ pub async fn configure_winsw() -> Result<()> { Ok(()) } -#[derive(Clone, Debug, Deserialize, Default, Serialize)] +#[derive(Clone, Debug, Deserialize, Serialize)] pub struct AppData { pub discord_username: String, pub nodes_to_start: usize, @@ -106,37 +105,49 @@ pub struct AppData { pub storage_drive: Option, } +impl Default for AppData { + fn default() -> Self { + Self { + discord_username: "".to_string(), + nodes_to_start: 1, + storage_mountpoint: None, + storage_drive: None, + } + } +} + impl AppData { - pub fn load() -> Result { - let config_dir = - get_config_dir().map_err(|_| color_eyre::eyre::eyre!("Could not obtain config dir"))?; - let config_path = config_dir.join("app_data.json"); + pub fn load(custom_path: Option) -> Result { + let config_path = if let Some(path) = custom_path { + path + } else { + get_config_dir() + .map_err(|_| color_eyre::eyre::eyre!("Could not obtain config dir"))? + .join("app_data.json") + }; if !config_path.exists() { return Ok(Self::default()); } - let data = std::fs::read_to_string(config_path) + let data = std::fs::read_to_string(&config_path) .map_err(|_| color_eyre::eyre::eyre!("Failed to read app data file"))?; - let mut app_data: AppData = serde_json::from_str(&data) + let app_data: AppData = serde_json::from_str(&data) .map_err(|_| color_eyre::eyre::eyre!("Failed to parse app data"))?; - if app_data.storage_mountpoint.is_none() || app_data.storage_drive.is_none() { - // If the storage drive is not set, set it to the default mount point - let drive_info = system::get_default_mount_point()?; - app_data.storage_drive = Some(drive_info.0); - app_data.storage_mountpoint = Some(drive_info.1); - debug!("Setting storage drive to {:?}", app_data.storage_mountpoint); - } Ok(app_data) } - pub fn save(&self) -> Result<()> { - let config_dir = get_config_dir() - .map_err(|_| config::ConfigError::Message("Could not obtain data dir".to_string()))?; + pub fn save(&self, custom_path: Option) -> Result<()> { + let config_path = if let Some(path) = custom_path { + path + } else { + get_config_dir() + .map_err(|_| config::ConfigError::Message("Could not obtain data dir".to_string()))? + .join("app_data.json") + }; - let config_path = config_dir.join("app_data.json"); let serialized_config = serde_json::to_string_pretty(&self)?; std::fs::write(config_path, serialized_config)?; @@ -536,6 +547,7 @@ fn parse_color(s: &str) -> Option { #[cfg(test)] mod tests { use pretty_assertions::assert_eq; + use tempfile::tempdir; use super::*; @@ -681,4 +693,126 @@ mod tests { KeyEvent::new(KeyCode::Enter, KeyModifiers::ALT) ); } + + #[test] + fn test_app_data_file_does_not_exist() -> Result<()> { + let temp_dir = tempdir()?; + let non_existent_path = temp_dir.path().join("non_existent_app_data.json"); + + let app_data = AppData::load(Some(non_existent_path))?; + + assert_eq!(app_data.discord_username, ""); + assert_eq!(app_data.nodes_to_start, 1); + assert_eq!(app_data.storage_mountpoint, None); + assert_eq!(app_data.storage_drive, None); + + Ok(()) + } + + #[test] + fn test_app_data_partial_info() -> Result<()> { + let temp_dir = tempdir()?; + let partial_data_path = temp_dir.path().join("partial_app_data.json"); + + let partial_data = r#" + { + "discord_username": "test_user", + "nodes_to_start": 3 + } + "#; + + std::fs::write(&partial_data_path, partial_data)?; + + let app_data = AppData::load(Some(partial_data_path))?; + + assert_eq!(app_data.discord_username, "test_user"); + assert_eq!(app_data.nodes_to_start, 3); + assert_eq!(app_data.storage_mountpoint, None); + assert_eq!(app_data.storage_drive, None); + + Ok(()) + } + + #[test] + fn test_app_data_missing_mountpoint() -> Result<()> { + let temp_dir = tempdir()?; + let missing_mountpoint_path = temp_dir.path().join("missing_mountpoint_app_data.json"); + + let missing_mountpoint_data = r#" + { + "discord_username": "test_user", + "nodes_to_start": 3, + "storage_drive": "C:" + } + "#; + + std::fs::write(&missing_mountpoint_path, missing_mountpoint_data)?; + + let app_data = AppData::load(Some(missing_mountpoint_path))?; + + assert_eq!(app_data.discord_username, "test_user"); + assert_eq!(app_data.nodes_to_start, 3); + assert_eq!(app_data.storage_mountpoint, None); + assert_eq!(app_data.storage_drive, Some("C:".to_string())); + + Ok(()) + } + + #[test] + fn test_app_data_complete_info() -> Result<()> { + let temp_dir = tempdir()?; + let complete_data_path = temp_dir.path().join("complete_app_data.json"); + + let complete_data = r#" + { + "discord_username": "complete_user", + "nodes_to_start": 5, + "storage_mountpoint": "/mnt/data", + "storage_drive": "D:" + } + "#; + + std::fs::write(&complete_data_path, complete_data)?; + + let app_data = AppData::load(Some(complete_data_path))?; + + assert_eq!(app_data.discord_username, "complete_user"); + assert_eq!(app_data.nodes_to_start, 5); + assert_eq!( + app_data.storage_mountpoint, + Some(PathBuf::from("/mnt/data")) + ); + assert_eq!(app_data.storage_drive, Some("D:".to_string())); + + Ok(()) + } + + #[test] + fn test_app_data_save_and_load() -> Result<()> { + let temp_dir = tempdir()?; + let test_path = temp_dir.path().join("test_app_data.json"); + + let mut app_data = AppData::default(); + let var_name = &"save_load_user"; + app_data.discord_username = var_name.to_string(); + app_data.nodes_to_start = 4; + app_data.storage_mountpoint = Some(PathBuf::from("/mnt/test")); + app_data.storage_drive = Some("E:".to_string()); + + // Save to custom path + app_data.save(Some(test_path.clone()))?; + + // Load from custom path + let loaded_data = AppData::load(Some(test_path))?; + + assert_eq!(loaded_data.discord_username, "save_load_user"); + assert_eq!(loaded_data.nodes_to_start, 4); + assert_eq!( + loaded_data.storage_mountpoint, + Some(PathBuf::from("/mnt/test")) + ); + assert_eq!(loaded_data.storage_drive, Some("E:".to_string())); + + Ok(()) + } } diff --git a/node-launchpad/src/system.rs b/node-launchpad/src/system.rs index cb3bbdb681..7d57ae91e6 100644 --- a/node-launchpad/src/system.rs +++ b/node-launchpad/src/system.rs @@ -120,6 +120,18 @@ pub fn get_primary_mount_point() -> PathBuf { PathBuf::from("C:\\") } +/// Gets the name of the primary mount point. +pub fn get_primary_mount_point_name() -> Result { + let primary_mount_point = get_primary_mount_point(); + let available_drives = get_list_of_available_drives_and_available_space()?; + + available_drives + .iter() + .find(|(_, mount_point, _, _)| mount_point == &primary_mount_point) + .map(|(name, _, _, _)| name.clone()) + .ok_or_else(|| eyre!("Unable to find the name of the primary mount point")) +} + // Gets available disk space in bytes for the given mountpoint pub fn get_available_space_b(storage_mountpoint: &PathBuf) -> Result { let disks = Disks::new_with_refreshed_list(); @@ -137,7 +149,7 @@ pub fn get_available_space_b(storage_mountpoint: &PathBuf) -> Result { .list() .iter() .find(|disk| disk.mount_point() == storage_mountpoint) - .context("Cannot find the primary disk")? + .context("Cannot find the primary disk. Configuration file might be wrong.")? .available_space() as usize; Ok(available_space_b) From 1a431fdf6d5752980aa43169855df9304ffd425c Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Mon, 2 Sep 2024 11:57:12 +0100 Subject: [PATCH 05/35] chore(release): stable release 2024.08.2.4 ================== Crate Versions ================== sn_auditor: 0.2.4 sn_build_info: 0.1.11 sn_cli: 0.94.1 sn_client: 0.109.1 sn_faucet: 0.4.32 sn_logging: 0.2.32 sn_metrics: 0.1.12 nat-detection: 0.2.2 sn_networking: 0.17.2 sn_node: 0.110.1 node-launchpad: 0.3.13 sn_node_manager: 0.10.2 sn_node_rpc_client: 0.6.27 sn_peers_acquisition: 0.4.2 sn_protocol: 0.17.7 sn_registers: 0.3.17 sn_service_management: 0.3.10 sn_transfers: 0.18.10 test_utils: 0.4.3 token_supplies: 0.1.50 =================== Binary Versions =================== faucet: 0.4.32 nat-detection: 0.2.2 node-launchpad: 0.3.13 safe: 0.94.1 safenode: 0.110.1 safenode-manager: 0.10.2 safenode_rpc_client: 0.6.27 safenodemand: 0.10.2 sn_auditor: 0.2.4 --- CHANGELOG.md | 11 +++++++++++ Cargo.lock | 2 +- node-launchpad/Cargo.toml | 2 +- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 75abab8ee8..3b5160c157 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 *When editing this file, please respect a line length of 100.* +## 2024-09-02 + +### Launchpad + +#### Fixed + +- Some users encountered an error when the launchpad started, related to the storage mountpoint not + being set. We fix the error by providing default values for the mountpoint settings when the + `app_data.json` file doesn't exist (fresh install). In the case where it does exist, we validate + the contents. + ## 2024-08-27 ### Network diff --git a/Cargo.lock b/Cargo.lock index 9d4a76fc4b..a4257d633f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4691,7 +4691,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.3.13-rc.1" +version = "0.3.14-rc.1" dependencies = [ "ansi-to-tui", "atty", diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index 13f6803967..e20f76e214 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.3.13-rc.1" +version = "0.3.14-rc.1" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" From eef204a983a47e01d5a5be4459c8858203d3f85f Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Mon, 2 Sep 2024 16:22:00 +0100 Subject: [PATCH 06/35] chore(release): update cycle info This should have been done in the release commit, but it was forgotten. From 34ef1026bb7d53d0cdad3c7d2b19ab6bfa06c99b Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Mon, 2 Sep 2024 17:47:04 +0100 Subject: [PATCH 07/35] chore(release): release candidate 2024.09.1.2 ================== Crate Versions ================== sn_auditor: 0.3.0-rc.2 sn_build_info: 0.1.12-rc.2 sn_cli: 0.95.0-rc.2 sn_client: 0.110.0-rc.2 sn_faucet: 0.5.0-rc.2 sn_logging: 0.2.33-rc.2 sn_metrics: 0.1.13-rc.2 nat-detection: 0.2.3-rc.2 sn_networking: 0.18.0-rc.2 sn_node: 0.111.0-rc.2 node-launchpad: 0.3.14-rc.2 sn_node_manager: 0.10.3-rc.2 sn_node_rpc_client: 0.6.28-rc.2 sn_peers_acquisition: 0.5.0-rc.2 sn_protocol: 0.17.8-rc.2 sn_registers: 0.3.18-rc.2 sn_service_management: 0.3.11-rc.2 sn_transfers: 0.19.0-rc.2 test_utils: 0.4.4-rc.2 token_supplies: 0.1.51-rc.2 =================== Binary Versions =================== faucet: 0.5.0-rc.2 nat-detection: 0.2.3-rc.2 node-launchpad: 0.3.14-rc.2 safe: 0.95.0-rc.2 safenode: 0.111.0-rc.2 safenode-manager: 0.10.3-rc.2 safenode_rpc_client: 0.6.28-rc.2 safenodemand: 0.10.3-rc.2 sn_auditor: 0.3.0-rc.2 --- Cargo.lock | 40 ++++++++++++++++---------------- nat-detection/Cargo.toml | 4 ++-- node-launchpad/Cargo.toml | 8 +++---- release-cycle-info | 2 +- sn_auditor/Cargo.toml | 8 +++---- sn_build_info/Cargo.toml | 2 +- sn_cli/Cargo.toml | 14 +++++------ sn_client/Cargo.toml | 18 +++++++------- sn_faucet/Cargo.toml | 16 ++++++------- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 10 ++++---- sn_node/Cargo.toml | 24 +++++++++---------- sn_node_manager/Cargo.toml | 12 +++++----- sn_node_rpc_client/Cargo.toml | 16 ++++++------- sn_peers_acquisition/Cargo.toml | 4 ++-- sn_protocol/Cargo.toml | 8 +++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++---- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 2 +- token_supplies/Cargo.toml | 2 +- 22 files changed, 103 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a4257d633f..abdbd3cd97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4576,7 +4576,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.3-rc.1" +version = "0.2.3-rc.2" dependencies = [ "clap", "clap-verbosity-flag", @@ -4691,7 +4691,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.3.14-rc.1" +version = "0.3.14-rc.2" dependencies = [ "ansi-to-tui", "atty", @@ -6941,7 +6941,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.10.3-rc.1" +version = "0.10.3-rc.2" dependencies = [ "assert_cmd", "assert_fs", @@ -7003,7 +7003,7 @@ dependencies = [ [[package]] name = "sn_auditor" -version = "0.3.0-rc.1" +version = "0.3.0-rc.2" dependencies = [ "blsttc", "clap", @@ -7037,14 +7037,14 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.12-rc.1" +version = "0.1.12-rc.2" dependencies = [ "vergen", ] [[package]] name = "sn_cli" -version = "0.95.0-rc.1" +version = "0.95.0-rc.2" dependencies = [ "aes 0.7.5", "base64 0.22.1", @@ -7086,7 +7086,7 @@ dependencies = [ [[package]] name = "sn_client" -version = "0.110.0-rc.1" +version = "0.110.0-rc.2" dependencies = [ "assert_matches", "async-trait", @@ -7169,7 +7169,7 @@ dependencies = [ [[package]] name = "sn_faucet" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" dependencies = [ "assert_fs", "base64 0.22.1", @@ -7201,7 +7201,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.33-rc.1" +version = "0.2.33-rc.2" dependencies = [ "chrono", "color-eyre", @@ -7226,7 +7226,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.13-rc.1" +version = "0.1.13-rc.2" dependencies = [ "clap", "color-eyre", @@ -7240,7 +7240,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.18.0-rc.1" +version = "0.18.0-rc.2" dependencies = [ "aes-gcm-siv", "async-trait", @@ -7283,7 +7283,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.111.0-rc.1" +version = "0.111.0-rc.2" dependencies = [ "assert_fs", "assert_matches", @@ -7337,7 +7337,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.28-rc.1" +version = "0.6.28-rc.2" dependencies = [ "assert_fs", "async-trait", @@ -7364,7 +7364,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" dependencies = [ "clap", "lazy_static", @@ -7380,7 +7380,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.8-rc.1" +version = "0.17.8-rc.2" dependencies = [ "blsttc", "bytes", @@ -7409,7 +7409,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.3.18-rc.1" +version = "0.3.18-rc.2" dependencies = [ "blsttc", "crdts", @@ -7426,7 +7426,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.3.11-rc.1" +version = "0.3.11-rc.2" dependencies = [ "async-trait", "dirs-next", @@ -7452,7 +7452,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.19.0-rc.1" +version = "0.19.0-rc.2" dependencies = [ "assert_fs", "blsttc", @@ -7795,7 +7795,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.4-rc.1" +version = "0.4.4-rc.2" dependencies = [ "color-eyre", "dirs-next", @@ -7927,7 +7927,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.51-rc.1" +version = "0.1.51-rc.2" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 85bfa484cd..1b1deb6e4e 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.3-rc.1" +version = "0.2.3-rc.2" [[bin]] name = "nat-detection" @@ -28,7 +28,7 @@ libp2p = { version = "0.53", features = [ "macros", "upnp", ] } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.1" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.2" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index e20f76e214..d65e856476 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.3.14-rc.1" +version = "0.3.14-rc.2" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -48,10 +48,10 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn-node-manager = { version = "0.10.3-rc.1", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.0-rc.1", path = "../sn_peers_acquisition" } +sn-node-manager = { version = "0.10.3-rc.2", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.0-rc.2", path = "../sn_peers_acquisition" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.3.11-rc.1", path = "../sn_service_management" } +sn_service_management = { version = "0.3.11-rc.2", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/release-cycle-info b/release-cycle-info index f86d2490ca..f3989309f8 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -15,4 +15,4 @@ release-year: 2024 release-month: 09 release-cycle: 1 -release-cycle-counter: 1 +release-cycle-counter: 2 diff --git a/sn_auditor/Cargo.toml b/sn_auditor/Cargo.toml index d4aaef5fc5..393bc8a72a 100644 --- a/sn_auditor/Cargo.toml +++ b/sn_auditor/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Network Auditor" name = "sn_auditor" -version = "0.3.0-rc.1" +version = "0.3.0-rc.2" edition = "2021" homepage = "https://maidsafe.net" repository = "https://github.com/maidsafe/safe_network" @@ -31,9 +31,9 @@ graphviz-rust = { version = "0.9.0", optional = true } lazy_static = "1.4.0" serde = { version = "1.0.133", features = ["derive", "rc"] } serde_json = "1.0.108" -sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } tiny_http = { version = "0.12", features = ["ssl-rustls"] } tracing = { version = "~0.1.26" } tokio = { version = "1.32.0", features = [ diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index 3ae96627e0..9a26f7a426 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.12-rc.1" +version = "0.1.12-rc.2" [build-dependencies] vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } diff --git a/sn_cli/Cargo.toml b/sn_cli/Cargo.toml index f576dcec0f..5ce908e59f 100644 --- a/sn_cli/Cargo.toml +++ b/sn_cli/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_cli" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.95.0-rc.1" +version = "0.95.0-rc.2" [[bin]] path = "src/bin/main.rs" @@ -58,11 +58,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ rmp-serde = "1.1.1" rpassword = "7.3.1" serde = { version = "1.0.133", features = ["derive"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } -sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } tempfile = "3.6.0" tiny-keccak = "~2.0.2" tokio = { version = "1.32.0", features = [ @@ -84,7 +84,7 @@ eyre = "0.6.8" criterion = "0.5.1" tempfile = "3.6.0" rand = { version = "~0.8.5", features = ["small_rng"] } -sn_client = { path = "../sn_client", version = "0.110.0-rc.1", features = [ +sn_client = { path = "../sn_client", version = "0.110.0-rc.2", features = [ "test-utils", ] } diff --git a/sn_client/Cargo.toml b/sn_client/Cargo.toml index 690c71fc3c..e6296eb900 100644 --- a/sn_client/Cargo.toml +++ b/sn_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.110.0-rc.1" +version = "0.110.0-rc.2" [features] default = [] @@ -49,16 +49,16 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } tempfile = "3.6.0" thiserror = "1.0.23" tiny-keccak = "~2.0.2" tracing = { version = "~0.1.26" } xor_name = "5.0.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1", optional = true } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2", optional = true } eyre = { version = "0.6.8", optional = true } [dev-dependencies] @@ -67,8 +67,8 @@ dirs-next = "~2.0.0" # add rand to libp2p libp2p-identity = { version = "0.2.7", features = ["rand"] } sn_client = { path = "../sn_client", features = ["test-utils"] } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2", features = [ "test-utils", ] } @@ -83,7 +83,7 @@ crate-type = ["cdylib", "rlib"] getrandom = { version = "0.2.12", features = ["js"] } wasm-bindgen = "0.2.90" wasm-bindgen-futures = "0.4.40" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } console_error_panic_hook = "0.1.6" tracing-wasm = "0.2.1" wasmtimer = "0.2.0" diff --git a/sn_faucet/Cargo.toml b/sn_faucet/Cargo.toml index 284bfb1615..7872b7e1e3 100644 --- a/sn_faucet/Cargo.toml +++ b/sn_faucet/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_faucet" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" [features] default = ["gifting"] @@ -37,13 +37,13 @@ indicatif = { version = "0.17.5", features = ["tokio"] } minreq = { version = "2.11.0", features = ["https-rustls"], optional = true } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } -sn_cli = { path = "../sn_cli", version = "0.95.0-rc.1" } -sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } +sn_cli = { path = "../sn_cli", version = "0.95.0-rc.2" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } tokio = { version = "1.32.0", features = ["parking_lot", "rt"] } tracing = { version = "~0.1.26" } url = "2.5.0" diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 4d56e4e5e2..85e941665f 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.33-rc.1" +version = "0.2.33-rc.2" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index b09fcf7275..a30cbe5d2d 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.13-rc.1" +version = "0.1.13-rc.2" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index e3934ceddb..9d8e5fec0c 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.18.0-rc.1" +version = "0.18.0-rc.2" [features] default = [] @@ -53,10 +53,10 @@ rand = { version = "~0.8.5", features = ["small_rng"] } rayon = "1.8.0" rmp-serde = "1.1.1" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path="../sn_build_info", version = "0.1.12-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } +sn_build_info = { path="../sn_build_info", version = "0.1.12-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index a1b40abfe1..d0464269d9 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.111.0-rc.1" +version = "0.111.0-rc.2" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -50,14 +50,14 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.2" } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ "io-util", @@ -84,11 +84,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", features = [ +sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 964e8a6cea..26662fbc69 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.10.3-rc.1" +version = "0.10.3-rc.2" [[bin]] name = "safenode-manager" @@ -44,12 +44,12 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1" } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.1" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.2" } sn-releases = "0.2.6" -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index 6c8f9cb0c4..19ae79b9f7 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.28-rc.1" +version = "0.6.28-rc.2" [[bin]] name = "safenode_rpc_client" @@ -23,13 +23,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version="0.53", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_client = { path = "../sn_client", version = "0.110.0-rc.1" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_node = { path = "../sn_node", version = "0.111.0-rc.1" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_node = { path = "../sn_node", version = "0.111.0-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index df24200840..5300740b21 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.0-rc.1" +version = "0.5.0-rc.2" [features] local-discovery = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version="0.53", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false} tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index e0208860d0..59b7c1f67b 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.8-rc.1" +version = "0.17.8-rc.2" [features] default = [] @@ -28,9 +28,9 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.1" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.1" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index 322cac35a4..7edab34ab6 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.18-rc.1" +version = "0.3.18-rc.2" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index f33caa5e49..a4fd4bf1b1 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.11-rc.1" +version = "0.3.11-rc.2" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.1" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.1", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.1" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index 91e85a9423..d82594116a 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.0-rc.1" +version = "0.19.0-rc.2" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 1f54157a93..b3683f3448 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.4-rc.1" +version = "0.4.4-rc.2" [dependencies] color-eyre = "~0.6.2" diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index 66e1ae054b..5798656b3c 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.51-rc.1" +version = "0.1.51-rc.2" [dependencies] From 6cb570da824f29cbba7fe88ee32a47e9a1701e4c Mon Sep 17 00:00:00 2001 From: qima Date: Wed, 4 Sep 2024 17:27:54 +0800 Subject: [PATCH 08/35] chore: refactor store_cost calculation --- sn_networking/src/record_store.rs | 76 +++++++++++++++---------------- sn_transfers/src/genesis.rs | 10 +++- 2 files changed, 46 insertions(+), 40 deletions(-) diff --git a/sn_networking/src/record_store.rs b/sn_networking/src/record_store.rs index a39a72f7a9..649f934dea 100644 --- a/sn_networking/src/record_store.rs +++ b/sn_networking/src/record_store.rs @@ -9,9 +9,9 @@ use crate::cmd::LocalSwarmCmd; use crate::driver::MAX_PACKET_SIZE; +use crate::send_local_swarm_cmd; use crate::target_arch::{spawn, Instant}; use crate::{event::NetworkEvent, log_markers::Marker}; -use crate::{send_local_swarm_cmd, CLOSE_GROUP_SIZE}; use aes_gcm_siv::{ aead::{Aead, KeyInit, OsRng}, Aes256GcmSiv, Nonce, @@ -34,7 +34,7 @@ use sn_protocol::{ storage::{RecordHeader, RecordKind, RecordType}, NetworkAddress, PrettyPrintRecordKey, }; -use sn_transfers::{NanoTokens, QuotingMetrics, TOTAL_SUPPLY}; +use sn_transfers::{NanoTokens, QuotingMetrics}; use std::collections::VecDeque; use std::{ borrow::Cow, @@ -62,6 +62,12 @@ const MAX_RECORDS_CACHE_SIZE: usize = 100; /// File name of the recorded historical quoting metrics. const HISTORICAL_QUOTING_METRICS_FILENAME: &str = "historic_quoting_metrics"; +/// Max store cost for a chunk. +const MAX_STORE_COST: u64 = 1_000_000; + +// Min store cost for a chunk. +const MIN_STORE_COST: u64 = 1; + /// A `RecordStore` that stores records on disk. pub struct NodeRecordStore { /// The identity of the peer owning the store. @@ -937,35 +943,27 @@ pub fn calculate_cost_for_records(quoting_metrics: &QuotingMetrics) -> u64 { let max_records = quoting_metrics.max_records; let live_time = quoting_metrics.live_time; - let ori_cost = (10 * records_stored) as u64; - let divider = max(1, records_stored / max(1, received_payment_count)) as u64; + let ori_cost = positive_input_0_1_sigmoid(records_stored as f64 / max_records as f64) + * MAX_STORE_COST as f64; + + let divider = max(1, records_stored / max(1, received_payment_count)); // Gaining one step for every day that staying in the network let reward_steps: u64 = live_time / (24 * 3600); - let base_multiplier = 1.1_f32; - let rewarder = max(1, base_multiplier.powf(reward_steps as f32) as u64); - - // Fine tuning here helps to get a desired curve: - // 1, Close to the max supply (4.3E+18) when stored records reaching full. - // 2, Charging around `token`s near the situation of 80% storage reached. - // - // 1.02.powf(1638) = 1.25E+14 => charge_at_full = 10 * MAX_RECORDS * 1.25E+14 = 5.4E+18 - // 1.02.powf(820) = 1.1E+7 => charge_at_80_percent = 10 * 0.8 * MAX_RECORDS * 1.1E+7 = 3.6E+11 (360 tokens) - let base_multiplier = 1.0225_f32; - - // Given currently the max_records is set at MAX_RECORDS, - // hence setting the multiplier trigger at 60% of the max_records - let exponential_pricing_trigger = 6 * max_records / 10; - - let multiplier = max( - 1, - base_multiplier.powf(records_stored.saturating_sub(exponential_pricing_trigger) as f32) - as u64, - ); + let base_multiplier = 1.01_f64; + let rewarder = max(1, base_multiplier.powf(reward_steps as f64) as u64); - let charge = max(10, ori_cost.saturating_mul(multiplier) / divider / rewarder); + // Deploy a lower cap safe_guard to the store_cost + let charge = max( + MIN_STORE_COST, + (ori_cost / divider as f64 / rewarder as f64) as u64, + ); // Deploy an upper cap safe_guard to the store_cost - min(TOTAL_SUPPLY / CLOSE_GROUP_SIZE as u64, charge) + min(MAX_STORE_COST, charge) +} + +fn positive_input_0_1_sigmoid(x: f64) -> f64 { + 1.0 / (1.0 + (-30.0 * (x - 0.5)).exp()) } #[allow(trivial_casts)] @@ -1026,7 +1024,7 @@ mod tests { received_payment_count: MAX_RECORDS_COUNT + 1, live_time: 1, }); - assert_eq!(sut, TOTAL_SUPPLY / CLOSE_GROUP_SIZE as u64); + assert_eq!(sut, MAX_STORE_COST - 1); } #[test] @@ -1039,7 +1037,7 @@ mod tests { live_time: 1, }); // at this point we should be at max cost - assert_eq!(sut, 20480); + assert_eq!(sut, 500000); } #[test] fn test_calculate_60_percent_cost_for_records() { @@ -1051,7 +1049,7 @@ mod tests { live_time: 1, }); // at this point we should be at max cost - assert_eq!(sut, 24570); + assert_eq!(sut, 952375); } #[test] @@ -1064,7 +1062,7 @@ mod tests { live_time: 1, }); // at this point we should be at max cost - assert_eq!(sut, 2528900); + assert_eq!(sut, 988981); } #[test] @@ -1077,7 +1075,7 @@ mod tests { live_time: 1, }); // at this point we should be at max cost - assert_eq!(sut, 262645870); + assert_eq!(sut, 997523); } #[test] @@ -1090,7 +1088,7 @@ mod tests { live_time: 1, }); // at this point we should be at max cost - assert_eq!(sut, 2689140767040); + assert_eq!(sut, 999875); } #[test] @@ -1103,7 +1101,7 @@ mod tests { live_time: 1, }); // at this point we should be at max cost - assert_eq!(sut, 27719885856440320); + assert_eq!(sut, 999993); } #[test] @@ -1114,7 +1112,7 @@ mod tests { received_payment_count: 0, live_time: 1, }); - assert_eq!(sut, 10); + assert_eq!(sut, MIN_STORE_COST); } #[test] @@ -1366,7 +1364,9 @@ mod tests { for _ in 0..max_records - 1 { let record_key = NetworkAddress::from_peer(PeerId::random()).to_record_key(); let value = match try_serialize_record( - &(0..50).map(|_| rand::random::()).collect::(), + &(0..max_records) + .map(|_| rand::random::()) + .collect::(), RecordKind::Chunk, ) { Ok(value) => value.to_vec(), @@ -1575,14 +1575,14 @@ mod tests { // Execute for 50 iterations, which allows the test can be executed in normal CI runs. if iteration == 50 { - assert_eq!(0, empty_earned_nodes, "every node has earnt _something_"); + assert!(empty_earned_nodes < 5, "0.25% of nodes still not earning"); assert!( (max_store_cost / min_store_cost) < 100, - "store cost is balanced" + "store cost is not balanced" ); assert!( (max_earned / min_earned) < 1000, - "earning distribution is well balanced" + "earning distribution is not balanced" ); break; } diff --git a/sn_transfers/src/genesis.rs b/sn_transfers/src/genesis.rs index 959fc8dc2e..56d96f5990 100644 --- a/sn_transfers/src/genesis.rs +++ b/sn_transfers/src/genesis.rs @@ -40,12 +40,18 @@ const DEFAULT_LIVE_GENESIS_SK: &str = /// Default genesis PK for testing purposes. Be sure to pass the correct `GENESIS_PK` value via env for release. const DEFAULT_LIVE_GENESIS_PK: &str = "9934c21469a68415e6b06a435709e16bff6e92bf302aeb0ea9199d2d06a55f1b1a21e155853d3f94ae31f8f313f886ee"; // DevSkim: ignore DS173237 +/// MIN_STORE_COST is 1, hence to have a MIN_ROYALTY_FEE to avoid zero royalty_fee. +const MIN_ROYALTY_FEE: u64 = 1; + /// Based on the given store cost, it calculates what's the expected amount to be paid as network royalties. /// Network royalties fee is expected to be 15% of the payment amount, i.e. 85% of store cost + 15% royalties fees. pub fn calculate_royalties_fee(store_cost: NanoTokens) -> NanoTokens { - let fees_amount = (store_cost.as_nano() as f64 * 0.15) / 0.85; + let fees_amount = std::cmp::max( + MIN_ROYALTY_FEE, + ((store_cost.as_nano() as f64 * 0.15) / 0.85) as u64, + ); // we round down the calculated amount - NanoTokens::from(fees_amount as u64) + NanoTokens::from(fees_amount) } /// A specialised `Result` type for genesis crate. From 8d8e6f96bc98752af52521171ca901e0d95a3c69 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Tue, 20 Aug 2024 12:38:51 +0200 Subject: [PATCH 09/35] feat(launchpad): connection mode and port rage selection --- node-launchpad/.config/config.json5 | 6 + node-launchpad/src/action.rs | 9 +- node-launchpad/src/app.rs | 38 +- node-launchpad/src/components/options.rs | 134 +++++- node-launchpad/src/components/popup.rs | 2 + .../src/components/popup/change_drive.rs | 8 +- .../src/components/popup/connection_mode.rs | 395 ++++++++++++++++++ .../src/components/popup/port_range.rs | 0 node-launchpad/src/components/status.rs | 43 +- node-launchpad/src/config.rs | 21 +- node-launchpad/src/connection_mode.rs | 71 ++++ node-launchpad/src/lib.rs | 1 + node-launchpad/src/mode.rs | 2 + 13 files changed, 704 insertions(+), 26 deletions(-) create mode 100644 node-launchpad/src/components/popup/connection_mode.rs create mode 100644 node-launchpad/src/components/popup/port_range.rs create mode 100644 node-launchpad/src/connection_mode.rs diff --git a/node-launchpad/.config/config.json5 b/node-launchpad/.config/config.json5 index 8bbd2f356e..58db17d7bb 100644 --- a/node-launchpad/.config/config.json5 +++ b/node-launchpad/.config/config.json5 @@ -39,6 +39,12 @@ "": {"OptionsActions":"TriggerChangeDrive"}, "": {"OptionsActions":"TriggerChangeDrive"}, "": {"OptionsActions":"TriggerChangeDrive"}, + "": {"OptionsActions":"TriggerChangeConnectionMode"}, + "": {"OptionsActions":"TriggerChangeConnectionMode"}, + "": {"OptionsActions":"TriggerChangeConnectionMode"}, + "": {"OptionsActions":"TriggerChangePortRange"}, + "": {"OptionsActions":"TriggerChangePortRange"}, + "": {"OptionsActions":"TriggerChangePortRange"}, "": {"OptionsActions":"TriggerBetaProgramme"}, "": {"OptionsActions":"TriggerBetaProgramme"}, "": {"OptionsActions":"TriggerBetaProgramme"}, diff --git a/node-launchpad/src/action.rs b/node-launchpad/src/action.rs index e58402a462..043089c842 100644 --- a/node-launchpad/src/action.rs +++ b/node-launchpad/src/action.rs @@ -7,6 +7,7 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::{ + connection_mode::ConnectionMode, mode::{InputMode, Scene}, node_stats::NodeStats, }; @@ -22,9 +23,11 @@ pub enum Action { SwitchScene(Scene), SwitchInputMode(InputMode), + StoreStorageDrive(PathBuf, String), + StoreConnectionMode(ConnectionMode), + StorePortRange(u16, u16), StoreDiscordUserName(String), StoreNodesToStart(usize), - StoreStorageDrive(PathBuf, String), Tick, Render, @@ -61,9 +64,13 @@ pub enum OptionsActions { ResetNodes, TriggerChangeDrive, + TriggerChangeConnectionMode, + TriggerChangePortRange, TriggerBetaProgramme, TriggerResetNodes, TriggerAccessLogs, + UpdateConnectionMode(ConnectionMode), + UpdatePortRange(u16, u16), UpdateBetaProgrammeUsername(String), UpdateStorageDrive(PathBuf, String), } diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index 09053998fd..6e1342e848 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -15,12 +15,13 @@ use crate::{ options::Options, popup::{ beta_programme::BetaProgramme, change_drive::ChangeDrivePopup, - manage_nodes::ManageNodes, reset_nodes::ResetNodesPopup, + connection_mode::ChangeConnectionModePopUp, manage_nodes::ManageNodes, + reset_nodes::ResetNodesPopup, }, - status::Status, Component, }, config::{get_launchpad_nodes_data_dir_path, AppData, Config}, + connection_mode::ConnectionMode, mode::{InputMode, Scene}, style::SPACE_CADET, system::{get_default_mount_point, get_primary_mount_point, get_primary_mount_point_name}, @@ -71,6 +72,11 @@ impl App { debug!("Data dir path for nodes: {data_dir_path:?}"); // App data validations + let connection_mode = app_data + .connection_mode + .unwrap_or(ConnectionMode::Automatic); + let port_from = app_data.port_from.unwrap_or(PORT_MIN); + let port_to = app_data.port_to.unwrap_or(PORT_MAX); let storage_mountpoint = app_data .storage_mountpoint .clone() @@ -87,12 +93,18 @@ impl App { peers_args, safenode_path, data_dir_path, + connection_mode, + Some(port_from), + Some(port_to), ) .await?; let options = Options::new( storage_mountpoint.clone(), storage_drive.clone(), app_data.discord_username.clone(), + connection_mode, + Some(port_from), + Some(port_to), ) .await?; let help = Help::new().await?; @@ -102,6 +114,8 @@ impl App { let discord_username_input = BetaProgramme::new(app_data.discord_username.clone()); let manage_nodes = ManageNodes::new(app_data.nodes_to_start, storage_mountpoint.clone())?; let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; + let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; + let beta_programme = BetaProgramme::new(app_data.discord_username.clone()); Ok(Self { config, @@ -115,9 +129,10 @@ impl App { Box::new(help), // Popups Box::new(change_drive), + Box::new(change_connection_mode), + Box::new(beta_programme), Box::new(reset_nodes), Box::new(manage_nodes), - Box::new(discord_username_input), ], should_quit: false, should_suspend: false, @@ -229,6 +244,23 @@ impl App { self.input_mode = mode; } // Storing Application Data + Action::StoreStorageDrive(ref drive_mountpoint, ref drive_name) => { + debug!("Storing storage drive: {drive_mountpoint:?}, {drive_name:?}"); + self.app_data.storage_mountpoint = Some(drive_mountpoint.clone()); + self.app_data.storage_drive = Some(drive_name.as_str().to_string()); + self.app_data.save(None)?; + } + Action::StoreConnectionMode(ref mode) => { + debug!("Storing connection mode: {mode:?}"); + self.app_data.connection_mode = Some(mode.clone()); + self.app_data.save(None)?; + } + Action::StorePortRange(from, to) => { + debug!("Storing port range: {from:?}, {to:?}"); + self.app_data.port_from = Some(from); + self.app_data.port_to = Some(to); + self.app_data.save(None)?; + } Action::StoreDiscordUserName(ref username) => { debug!("Storing discord username: {username:?}"); self.app_data.discord_username.clone_from(username); diff --git a/node-launchpad/src/components/options.rs b/node-launchpad/src/components/options.rs index e3dc97764a..a19be98b4b 100644 --- a/node-launchpad/src/components/options.rs +++ b/node-launchpad/src/components/options.rs @@ -15,6 +15,7 @@ use super::{header::SelectedMenuItem, Component}; use crate::{ action::{Action, OptionsActions}, components::header::Header, + connection_mode::ConnectionMode, mode::{InputMode, Scene}, style::{EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VERY_LIGHT_AZURE, VIVID_SKY_BLUE}, system, @@ -26,6 +27,10 @@ pub struct Options { pub storage_mountpoint: PathBuf, pub storage_drive: String, pub discord_username: String, + pub connection_mode: ConnectionMode, + pub port_edit: bool, + pub port_from: Option, + pub port_to: Option, pub active: bool, pub action_tx: Option>, } @@ -35,11 +40,18 @@ impl Options { storage_mountpoint: PathBuf, storage_drive: String, discord_username: String, + connection_mode: ConnectionMode, + port_from: Option, + port_to: Option, ) -> Result { Ok(Self { storage_mountpoint, storage_drive, discord_username, + connection_mode, + port_edit: false, + port_from, + port_to, active: false, action_tx: None, }) @@ -47,10 +59,6 @@ impl Options { } impl Component for Options { - fn init(&mut self, _area: Rect) -> Result<()> { - Ok(()) - } - fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> { if !self.active { return Ok(()); @@ -61,7 +69,7 @@ impl Component for Options { .constraints( [ Constraint::Length(1), - Constraint::Length(5), + Constraint::Length(9), Constraint::Length(5), Constraint::Length(5), Constraint::Length(5), @@ -76,7 +84,7 @@ impl Component for Options { // Storage Drive let block1 = Block::default() - .title(" Storage Drive ") + .title(" Device Options ") .title_style(Style::default().bold().fg(GHOST_WHITE)) .style(Style::default().fg(GHOST_WHITE)) .borders(Borders::ALL) @@ -86,8 +94,16 @@ impl Component for Options { Row::new(vec![ Cell::from(Span::raw(" ")), // Empty row for padding Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), ]), Row::new(vec![ + Cell::from( + Line::from(vec![Span::styled( + " Storage Drive: ", + Style::default().fg(LIGHT_PERIWINKLE), + )]) + .alignment(Alignment::Left), + ), Cell::from( Line::from(vec![Span::styled( format!(" {} ", self.storage_drive), @@ -103,15 +119,82 @@ impl Component for Options { .alignment(Alignment::Right), ), ]), + Row::new(vec![ + Cell::from(Span::raw(" ")), // Empty row for padding + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + ]), + Row::new(vec![ + Cell::from( + Line::from(vec![Span::styled( + " Connection Mode: ", + Style::default().fg(LIGHT_PERIWINKLE), + )]) + .alignment(Alignment::Left), + ), + Cell::from( + Line::from(vec![Span::styled( + format!(" {} ", self.connection_mode), + Style::default().fg(VIVID_SKY_BLUE), + )]) + .alignment(Alignment::Left), + ), + Cell::from( + Line::from(vec![ + Span::styled(" Change Mode ", Style::default().fg(VERY_LIGHT_AZURE)), + Span::styled(" [Ctrl+K] ", Style::default().fg(GHOST_WHITE)), + ]) + .alignment(Alignment::Right), + ), + ]), + Row::new(vec![ + Cell::from(Span::raw(" ")), // Empty row for padding + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + ]), + Row::new(vec![ + Cell::from( + Line::from(vec![Span::styled( + " Port Range: ", + Style::default().fg(LIGHT_PERIWINKLE), + )]) + .alignment(Alignment::Left), + ), + Cell::from( + Line::from(vec![Span::styled( + format!( + " {}-{} ", + self.port_from.unwrap_or(0), + self.port_to.unwrap_or(0) + ), + Style::default().fg(VIVID_SKY_BLUE), + )]) + .alignment(Alignment::Left), + ), + Cell::from( + Line::from(vec![ + Span::styled( + " Edit Port Range ", + Style::default().fg(VERY_LIGHT_AZURE), + ), + Span::styled(" [Ctrl+P] ", Style::default().fg(GHOST_WHITE)), + ]) + .alignment(Alignment::Right), + ), + ]), + ], + &[ + Constraint::Length(18), + Constraint::Percentage(25), + Constraint::Fill(1), ], - &[Constraint::Percentage(50), Constraint::Percentage(50)], ) .block(block1) .style(Style::default().fg(GHOST_WHITE)); - // Beta Rewards Program — Discord Username + // Beta Rewards Program let block2 = Block::default() - .title(" Beta Rewards Program — Discord Username ") + .title(" Beta Rewards Program ") .title_style(Style::default().bold().fg(GHOST_WHITE)) .style(Style::default().fg(GHOST_WHITE)) .borders(Borders::ALL) @@ -122,8 +205,16 @@ impl Component for Options { // Empty row for padding Cell::from(Span::raw(" ")), Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), ]), Row::new(vec![ + Cell::from( + Line::from(vec![Span::styled( + " Discord Username: ", + Style::default().fg(LIGHT_PERIWINKLE), + )]) + .alignment(Alignment::Left), + ), Cell::from( Line::from(vec![Span::styled( format!(" {} ", self.discord_username), @@ -143,7 +234,11 @@ impl Component for Options { ), ]), ], - &[Constraint::Percentage(50), Constraint::Percentage(50)], + &[ + Constraint::Length(18), + Constraint::Percentage(25), + Constraint::Fill(1), + ], ) .block(block2) .style(Style::default().fg(GHOST_WHITE)); @@ -232,9 +327,11 @@ impl Component for Options { match action { Action::SwitchScene(scene) => match scene { Scene::Options + | Scene::ChangeDrivePopUp + | Scene::ChangeConnectionModePopUp + | Scene::ChangePortsPopUp | Scene::BetaProgrammePopUp - | Scene::ResetNodesPopUp - | Scene::ChangeDrivePopUp => { + | Scene::ResetNodesPopUp => { self.active = true; // make sure we're in navigation mode return Ok(Some(Action::SwitchInputMode(InputMode::Navigation))); @@ -249,6 +346,19 @@ impl Component for Options { self.storage_mountpoint = mountpoint; self.storage_drive = drive; } + OptionsActions::TriggerChangeConnectionMode => { + return Ok(Some(Action::SwitchScene(Scene::ChangeConnectionModePopUp))); + } + OptionsActions::UpdateConnectionMode(mode) => { + self.connection_mode = mode; + } + OptionsActions::TriggerChangePortRange => { + return Ok(Some(Action::SwitchScene(Scene::ChangePortsPopUp))); + } + OptionsActions::UpdatePortRange(from, to) => { + self.port_from = Some(from); + self.port_to = Some(to); + } OptionsActions::TriggerBetaProgramme => { return Ok(Some(Action::SwitchScene(Scene::BetaProgrammePopUp))); } diff --git a/node-launchpad/src/components/popup.rs b/node-launchpad/src/components/popup.rs index 11c2bf9a3d..703ff50eae 100644 --- a/node-launchpad/src/components/popup.rs +++ b/node-launchpad/src/components/popup.rs @@ -8,5 +8,7 @@ pub mod beta_programme; pub mod change_drive; +pub mod connection_mode; pub mod manage_nodes; +pub mod port_range; pub mod reset_nodes; diff --git a/node-launchpad/src/components/popup/change_drive.rs b/node-launchpad/src/components/popup/change_drive.rs index 7ae9ba1d51..02d2ae13e5 100644 --- a/node-launchpad/src/components/popup/change_drive.rs +++ b/node-launchpad/src/components/popup/change_drive.rs @@ -54,7 +54,7 @@ impl ChangeDrivePopup { pub fn new(storage_mountpoint: PathBuf) -> Result { let drives_and_space = system::get_list_of_available_drives_and_available_space()?; - let mut selected_drive: DriveItem = DriveItem::default(); + let mut selected_connection_mode: DriveItem = DriveItem::default(); // Create a vector of DriveItem from drives_and_space let drives_items: Vec = drives_and_space .iter() @@ -66,7 +66,7 @@ impl ChangeDrivePopup { mountpoint: mountpoint.clone(), size: size_str, status: if mountpoint == &storage_mountpoint { - selected_drive = DriveItem { + selected_connection_mode = DriveItem { name: drive_name.to_string(), mountpoint: mountpoint.clone(), size: size_str_cloned, @@ -89,8 +89,8 @@ impl ChangeDrivePopup { active: false, state: ChangeDriveState::Selection, items, - drive_selection: selected_drive.clone(), - drive_selection_initial_state: selected_drive.clone(), + drive_selection: selected_connection_mode.clone(), + drive_selection_initial_state: selected_connection_mode.clone(), can_select: false, }) } diff --git a/node-launchpad/src/components/popup/connection_mode.rs b/node-launchpad/src/components/popup/connection_mode.rs new file mode 100644 index 0000000000..9b0c4d3d08 --- /dev/null +++ b/node-launchpad/src/components/popup/connection_mode.rs @@ -0,0 +1,395 @@ +// Copyright 2024 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3. +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. Please review the Licences for the specific language governing +// permissions and limitations relating to use of the SAFE Network Software. + +use std::default::Default; + +use super::super::utils::centered_rect_fixed; + +use color_eyre::Result; +use crossterm::event::{KeyCode, KeyEvent}; +use ratatui::{ + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Modifier, Style, Stylize}, + text::{Line, Span}, + widgets::{Block, Borders, HighlightSpacing, List, ListItem, ListState, Padding, Paragraph}, +}; +use strum::IntoEnumIterator; + +use crate::{ + action::{Action, OptionsActions}, + components::Component, + connection_mode::ConnectionMode, + mode::{InputMode, Scene}, + style::{ + clear_area, COOL_GREY, DARK_GUNMETAL, EUCALYPTUS, GHOST_WHITE, INDIGO, LIGHT_PERIWINKLE, + SPACE_CADET, VIVID_SKY_BLUE, + }, +}; + +#[derive(Default)] +pub struct ChangeConnectionModePopUp { + active: bool, + items: StatefulList, + connection_mode_selection: ConnectionModeItem, + connection_mode_initial_state: ConnectionModeItem, + can_select: bool, // If the user can select the connection mode +} + +impl ChangeConnectionModePopUp { + pub fn new(connection_mode: ConnectionMode) -> Result { + let mut selected_connection_mode: ConnectionModeItem = ConnectionModeItem::default(); + let connection_modes_items: Vec = ConnectionMode::iter() + .map(|connection_mode_item| ConnectionModeItem { + connection_mode: connection_mode_item.clone(), + status: if connection_mode == connection_mode_item { + selected_connection_mode = ConnectionModeItem { + connection_mode: connection_mode_item, + status: ConnectionModeStatus::Selected, + }; + ConnectionModeStatus::Selected + } else { + ConnectionModeStatus::NotSelected + }, + }) + .collect::>(); + debug!("Connection Mode in Config: {:?}", connection_mode); + let items = StatefulList::with_items(connection_modes_items); + Ok(Self { + active: false, + items, + connection_mode_selection: selected_connection_mode.clone(), + connection_mode_initial_state: selected_connection_mode.clone(), + can_select: false, + }) + } + + // --- Interactions with the List of modes --- + + /// Deselects all modes in the list of items + /// + fn deselect_all(&mut self) { + for item in &mut self.items.items { + item.status = ConnectionModeStatus::NotSelected; + } + } + /// Assigns to self.connection_mode_selection the selected connection mode in the list + /// + #[allow(dead_code)] + fn assign_connection_mode_selection(&mut self) { + self.deselect_all(); + if let Some(i) = self.items.state.selected() { + self.items.items[i].status = ConnectionModeStatus::Selected; + self.connection_mode_selection = self.items.items[i].clone(); + } + } + /// Highlights the connection mode that is currently selected in the list of items. + /// + fn select_connection_mode(&mut self) { + self.deselect_all(); + for (index, item) in self.items.items.iter_mut().enumerate() { + if item.connection_mode == self.connection_mode_selection.connection_mode { + item.status = ConnectionModeStatus::Selected; + self.items.state.select(Some(index)); + break; + } + } + } + /// Returns the highlighted connection mode in the list of items. + /// + fn return_selection(&mut self) -> ConnectionModeItem { + if let Some(i) = self.items.state.selected() { + return self.items.items[i].clone(); + } + ConnectionModeItem::default() + } +} + +impl Component for ChangeConnectionModePopUp { + fn handle_key_events(&mut self, key: KeyEvent) -> Result> { + if !self.active { + return Ok(vec![]); + } + let send_back: Vec = match key.code { + KeyCode::Enter => { + // We allow action if we have more than one connection mode and the action is not + // over the connection mode already selected + let connection_mode = self.return_selection(); + if connection_mode.connection_mode != self.connection_mode_selection.connection_mode + { + debug!( + "Got Enter and there's a new selection, storing value and switching to Options" + ); + debug!("Connection Mode selected: {:?}", connection_mode); + self.connection_mode_initial_state = self.connection_mode_selection.clone(); + self.assign_connection_mode_selection(); + vec![ + Action::StoreConnectionMode( + self.connection_mode_selection.connection_mode.clone(), + ), + Action::OptionsActions(OptionsActions::UpdateConnectionMode( + connection_mode.connection_mode, + )), + Action::SwitchScene(Scene::Options), + ] + } else { + debug!("Got Enter, but no new selection. We should not do anything"); + vec![Action::SwitchScene(Scene::ChangeConnectionModePopUp)] + } + } + KeyCode::Esc => { + debug!("Got Esc, switching to Options"); + vec![Action::SwitchScene(Scene::Options)] + } + KeyCode::Up => { + if self.items.items.len() > 1 { + self.items.previous(); + let connection_mode = self.return_selection(); + self.can_select = connection_mode.connection_mode + != self.connection_mode_selection.connection_mode; + } + vec![] + } + KeyCode::Down => { + if self.items.items.len() > 1 { + self.items.next(); + let connection_mode = self.return_selection(); + self.can_select = connection_mode.connection_mode + != self.connection_mode_selection.connection_mode; + } + vec![] + } + _ => { + vec![] + } + }; + Ok(send_back) + } + + fn update(&mut self, action: Action) -> Result> { + let send_back = match action { + Action::SwitchScene(scene) => match scene { + Scene::ChangeConnectionModePopUp => { + self.active = true; + self.can_select = false; + self.select_connection_mode(); + Some(Action::SwitchInputMode(InputMode::Entry)) + } + _ => { + self.active = false; + None + } + }, + // Useful when the user has selected a connection mode but didn't confirm it + Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { + self.connection_mode_selection.connection_mode = connection_mode; + self.select_connection_mode(); + None + } + _ => None, + }; + Ok(send_back) + } + + fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { + if !self.active { + return Ok(()); + } + + let layer_zero = centered_rect_fixed(52, 15, area); + + let layer_one = Layout::new( + Direction::Vertical, + [ + // Padding from title to the table + Constraint::Length(1), + // Table + Constraint::Min(1), + // for the pop_up_border + Constraint::Length(1), + ], + ) + .split(layer_zero); + + let pop_up_border: Paragraph = Paragraph::new("").block( + Block::default() + .borders(Borders::ALL) + .title(" Connection Mode ") + .title_style(Style::new().fg(VIVID_SKY_BLUE)) + .padding(Padding::uniform(2)) + .border_style(Style::new().fg(VIVID_SKY_BLUE)) + .bg(DARK_GUNMETAL), + ); + clear_area(f, layer_zero); + + let layer_two = Layout::new( + Direction::Vertical, + [ + // for the table + Constraint::Length(10), + // gap + Constraint::Length(3), + // for the buttons + Constraint::Length(1), + ], + ) + .split(layer_one[1]); + + // Connection Mode selector + let items: Vec = self + .items + .items + .iter() + .enumerate() + .map(|(i, connection_mode_item)| { + connection_mode_item.to_list_item(i, layer_two[0].width as usize) + }) + .collect(); + + let items = List::new(items) + .block(Block::default().padding(Padding::uniform(1))) + .highlight_style( + Style::default() + .add_modifier(Modifier::BOLD) + .add_modifier(Modifier::REVERSED) + .fg(INDIGO), + ) + .highlight_spacing(HighlightSpacing::Always); + + f.render_stateful_widget(items, layer_two[0], &mut self.items.state); + + // Dash + let dash = Block::new() + .borders(Borders::BOTTOM) + .border_style(Style::new().fg(GHOST_WHITE)); + f.render_widget(dash, layer_two[1]); + + // Buttons + let buttons_layer = + Layout::horizontal(vec![Constraint::Percentage(50), Constraint::Percentage(50)]) + .split(layer_two[2]); + + let button_no = Line::from(vec![Span::styled( + "Cancel [Esc]", + Style::default().fg(LIGHT_PERIWINKLE), + )]); + + f.render_widget( + Paragraph::new(button_no) + .block(Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Left), + buttons_layer[0], + ); + + let button_yes = Line::from(vec![ + Span::styled( + "Select ", + if self.can_select { + Style::default().fg(EUCALYPTUS) + } else { + Style::default().fg(COOL_GREY) + }, + ), + Span::styled("[Enter]", Style::default().fg(LIGHT_PERIWINKLE).bold()), + ]) + .alignment(Alignment::Right); + + f.render_widget( + Paragraph::new(button_yes) + .block(Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Right), + buttons_layer[1], + ); + + // We render now so the borders are on top of the other widgets + f.render_widget(pop_up_border, layer_zero); + + Ok(()) + } +} + +#[derive(Default)] +struct StatefulList { + state: ListState, + items: Vec, + last_selected: Option, +} + +impl StatefulList { + fn with_items(items: Vec) -> Self { + StatefulList { + state: ListState::default(), + items, + last_selected: None, + } + } + + fn next(&mut self) { + let i = match self.state.selected() { + Some(i) => { + if i >= self.items.len() - 1 { + 0 + } else { + i + 1 + } + } + None => self.last_selected.unwrap_or(0), + }; + self.state.select(Some(i)); + } + + fn previous(&mut self) { + let i = match self.state.selected() { + Some(i) => { + if i == 0 { + self.items.len() - 1 + } else { + i - 1 + } + } + None => self.last_selected.unwrap_or(0), + }; + self.state.select(Some(i)); + } +} + +#[derive(Default, Debug, Copy, Clone)] +enum ConnectionModeStatus { + Selected, + #[default] + NotSelected, +} + +#[derive(Default, Debug, Clone)] +pub struct ConnectionModeItem { + connection_mode: ConnectionMode, + status: ConnectionModeStatus, +} + +impl ConnectionModeItem { + fn to_list_item(&self, _index: usize, _width: usize) -> ListItem { + let line = match self.status { + ConnectionModeStatus::NotSelected => Line::from(vec![ + Span::raw(" "), + Span::styled( + self.connection_mode.to_string(), + Style::default().fg(VIVID_SKY_BLUE), + ), + ]), + ConnectionModeStatus::Selected => Line::from(vec![ + Span::styled(" ►", Style::default().fg(EUCALYPTUS)), + Span::raw(" "), + Span::styled( + self.connection_mode.to_string(), + Style::default().fg(VIVID_SKY_BLUE), + ), + ]), + }; + + ListItem::new(line).style(Style::default().bg(SPACE_CADET)) + } +} diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs new file mode 100644 index 0000000000..e69de29bb2 diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 402d131476..28fb98ce97 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -14,6 +14,7 @@ use super::{ }; use crate::action::OptionsActions; use crate::config::get_launchpad_nodes_data_dir_path; +use crate::connection_mode::ConnectionMode; use crate::{ action::{Action, StatusActions}, config::Config, @@ -69,6 +70,12 @@ pub struct Status { safenode_path: Option, // Path where the node data is stored data_dir_path: PathBuf, + // Connection mode + connection_mode: ConnectionMode, + // Port from + port_from: Option, + // Port to + port_to: Option, } #[derive(Clone)] @@ -85,6 +92,9 @@ impl Status { peers_args: PeersArgs, safenode_path: Option, data_dir_path: PathBuf, + connection_mode: ConnectionMode, + port_from: Option, + port_to: Option, ) -> Result { let mut status = Self { peers_args, @@ -102,6 +112,9 @@ impl Status { discord_username: discord_username.to_string(), safenode_path, data_dir_path, + connection_mode, + port_from, + port_to, }; let now = Instant::now(); @@ -376,6 +389,9 @@ impl Component for Status { info!("Got action to reset nodes"); reset_nodes(action_sender, false); } + Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { + self.connection_mode = connection_mode; + } _ => {} } Ok(None) @@ -454,6 +470,22 @@ impl Component for Status { Cell::new(memory_use_val).fg(GHOST_WHITE), ]); + let connection_mode_string = match self.connection_mode { + ConnectionMode::HomeNetwork => "Home Network", + ConnectionMode::UPnP => "UPnP", + ConnectionMode::CustomPorts => &format!( + "Custom Ports {}-{}", + self.port_from.unwrap_or(0), + self.port_to.unwrap_or(0) + ), + ConnectionMode::Automatic => "Automatic", + }; + + let connection_mode_row = Row::new(vec![ + Cell::new("Connection".to_string()).fg(GHOST_WHITE), + Cell::new(connection_mode_string).fg(GHOST_WHITE), + ]); + // Combine "Nanos Earned" and "Discord Username" into a single row let discord_username_title = Span::styled( "Discord Username: ".to_string(), @@ -473,7 +505,7 @@ impl Component for Status { ) }; - let total_nanos_earned_and_discord = Row::new(vec![ + let total_nanos_earned_and_discord_row = Row::new(vec![ Cell::new("Nanos Earned".to_string()).fg(VIVID_SKY_BLUE), Cell::new(self.node_stats.forwarded_rewards.to_string()) .fg(VIVID_SKY_BLUE) @@ -486,14 +518,15 @@ impl Component for Status { let stats_rows = vec![ storage_allocated_row, - memory_use_row.bottom_margin(1), - total_nanos_earned_and_discord, + memory_use_row, + connection_mode_row, + total_nanos_earned_and_discord_row, ]; let stats_width = [Constraint::Length(5)]; let column_constraints = [ + Constraint::Length(23), Constraint::Percentage(25), - Constraint::Percentage(5), - Constraint::Percentage(70), + Constraint::Fill(1), ]; let stats_table = Table::new(stats_rows, stats_width) .block( diff --git a/node-launchpad/src/config.rs b/node-launchpad/src/config.rs index 3db61eb518..1b19ab96e2 100644 --- a/node-launchpad/src/config.rs +++ b/node-launchpad/src/config.rs @@ -6,6 +6,8 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. +use crate::connection_mode::ConnectionMode; +use crate::system; use crate::system::get_primary_mount_point; use crate::{action::Action, mode::Scene}; use color_eyre::eyre::{eyre, Result}; @@ -103,6 +105,9 @@ pub struct AppData { pub nodes_to_start: usize, pub storage_mountpoint: Option, pub storage_drive: Option, + pub connection_mode: Option, + pub port_from: Option, + pub port_to: Option, } impl Default for AppData { @@ -112,6 +117,9 @@ impl Default for AppData { nodes_to_start: 1, storage_mountpoint: None, storage_drive: None, + connection_mode: None, + port_from: None, + port_to: None, } } } @@ -133,9 +141,20 @@ impl AppData { let data = std::fs::read_to_string(&config_path) .map_err(|_| color_eyre::eyre::eyre!("Failed to read app data file"))?; - let app_data: AppData = serde_json::from_str(&data) + let mut app_data: AppData = serde_json::from_str(&data) .map_err(|_| color_eyre::eyre::eyre!("Failed to parse app data"))?; + if app_data.storage_mountpoint.is_none() || app_data.storage_drive.is_none() { + // If the storage drive is not set, set it to the default mount point + let drive_info = system::get_default_mount_point()?; + app_data.storage_drive = Some(drive_info.0); + app_data.storage_mountpoint = Some(drive_info.1); + debug!("Setting storage drive to {:?}", app_data.storage_mountpoint); + } + + if app_data.connection_mode.is_none() { + app_data.connection_mode = Some(ConnectionMode::default()); + } Ok(app_data) } diff --git a/node-launchpad/src/connection_mode.rs b/node-launchpad/src/connection_mode.rs new file mode 100644 index 0000000000..fd8bd1093b --- /dev/null +++ b/node-launchpad/src/connection_mode.rs @@ -0,0 +1,71 @@ +use std::fmt::{Display, Formatter, Result}; + +use serde::{Deserialize, Serialize}; +use strum::EnumIter; + +#[derive(Clone, Debug, Default, EnumIter)] +pub enum ConnectionMode { + #[default] + Automatic, + HomeNetwork, + UPnP, + CustomPorts, +} + +impl Display for ConnectionMode { + fn fmt(&self, f: &mut Formatter) -> Result { + match self { + ConnectionMode::HomeNetwork => write!(f, "Home Network"), + ConnectionMode::UPnP => write!(f, "UPnP"), + ConnectionMode::CustomPorts => write!(f, "Custom Ports"), + ConnectionMode::Automatic => write!(f, "Automatic"), + } + } +} + +impl PartialEq for ConnectionMode { + fn eq(&self, other: &Self) -> bool { + matches!( + (self, other), + (ConnectionMode::HomeNetwork, ConnectionMode::HomeNetwork) + | (ConnectionMode::UPnP, ConnectionMode::UPnP) + | (ConnectionMode::CustomPorts, ConnectionMode::CustomPorts) + | (ConnectionMode::Automatic, ConnectionMode::Automatic) + ) + } +} + +impl Eq for ConnectionMode {} + +impl<'de> Deserialize<'de> for ConnectionMode { + fn deserialize(deserializer: D) -> std::result::Result + where + D: serde::Deserializer<'de>, + { + let s = String::deserialize(deserializer)?; + match s.as_str() { + "Home Network" => Ok(ConnectionMode::HomeNetwork), + "UPnP" => Ok(ConnectionMode::UPnP), + "Custom Ports" => Ok(ConnectionMode::CustomPorts), + "Automatic" => Ok(ConnectionMode::Automatic), + _ => Err(serde::de::Error::custom(format!( + "Invalid ConnectionMode: {s:?}" + ))), + } + } +} + +impl Serialize for ConnectionMode { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: serde::Serializer, + { + let s = match self { + ConnectionMode::HomeNetwork => "Home Network", + ConnectionMode::UPnP => "UPnP", + ConnectionMode::CustomPorts => "Custom Ports", + ConnectionMode::Automatic => "Automatic", + }; + serializer.serialize_str(s) + } +} diff --git a/node-launchpad/src/lib.rs b/node-launchpad/src/lib.rs index dc0ecc2e73..aa18661f27 100644 --- a/node-launchpad/src/lib.rs +++ b/node-launchpad/src/lib.rs @@ -10,6 +10,7 @@ pub mod action; pub mod app; pub mod components; pub mod config; +pub mod connection_mode; pub mod mode; pub mod node_mgmt; pub mod node_stats; diff --git a/node-launchpad/src/mode.rs b/node-launchpad/src/mode.rs index 641c433dfc..9a515383e5 100644 --- a/node-launchpad/src/mode.rs +++ b/node-launchpad/src/mode.rs @@ -15,6 +15,8 @@ pub enum Scene { Options, Help, ChangeDrivePopUp, + ChangeConnectionModePopUp, + ChangePortsPopUp, BetaProgrammePopUp, ManageNodesPopUp, ResetNodesPopUp, From 301dfc093c6169128a67c6a4cd9b5efa4b718588 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 21 Aug 2024 11:21:36 +0200 Subject: [PATCH 10/35] feat(launchpad): port selection screen and user flow --- node-launchpad/src/app.rs | 4 +- node-launchpad/src/components/options.rs | 41 ++- .../src/components/popup/connection_mode.rs | 8 +- .../src/components/popup/port_range.rs | 341 ++++++++++++++++++ node-launchpad/src/connection_mode.rs | 16 +- 5 files changed, 381 insertions(+), 29 deletions(-) diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index 6e1342e848..c0621eda10 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -16,7 +16,7 @@ use crate::{ popup::{ beta_programme::BetaProgramme, change_drive::ChangeDrivePopup, connection_mode::ChangeConnectionModePopUp, manage_nodes::ManageNodes, - reset_nodes::ResetNodesPopup, + port_range::PortRangePopUp, reset_nodes::ResetNodesPopup, }, Component, }, @@ -115,6 +115,7 @@ impl App { let manage_nodes = ManageNodes::new(app_data.nodes_to_start, storage_mountpoint.clone())?; let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; + let port_range = PortRangePopUp::new(connection_mode, port_from, port_to); let beta_programme = BetaProgramme::new(app_data.discord_username.clone()); Ok(Self { @@ -130,6 +131,7 @@ impl App { // Popups Box::new(change_drive), Box::new(change_connection_mode), + Box::new(port_range), Box::new(beta_programme), Box::new(reset_nodes), Box::new(manage_nodes), diff --git a/node-launchpad/src/components/options.rs b/node-launchpad/src/components/options.rs index a19be98b4b..cf5b8f5f3f 100644 --- a/node-launchpad/src/components/options.rs +++ b/node-launchpad/src/components/options.rs @@ -17,7 +17,9 @@ use crate::{ components::header::Header, connection_mode::ConnectionMode, mode::{InputMode, Scene}, - style::{EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VERY_LIGHT_AZURE, VIVID_SKY_BLUE}, + style::{ + COOL_GREY, EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VERY_LIGHT_AZURE, VIVID_SKY_BLUE, + }, system, }; use sn_node_manager::config::get_service_log_dir_path; @@ -161,23 +163,40 @@ impl Component for Options { .alignment(Alignment::Left), ), Cell::from( - Line::from(vec![Span::styled( - format!( - " {}-{} ", - self.port_from.unwrap_or(0), - self.port_to.unwrap_or(0) - ), - Style::default().fg(VIVID_SKY_BLUE), - )]) + Line::from(vec![ + if self.connection_mode == ConnectionMode::CustomPorts { + Span::styled( + format!( + " {}-{} ", + self.port_from.unwrap_or(0), + self.port_to.unwrap_or(0) + ), + Style::default().fg(VIVID_SKY_BLUE), + ) + } else { + Span::styled(" Auto ", Style::default().fg(COOL_GREY)) + }, + ]) .alignment(Alignment::Left), ), Cell::from( Line::from(vec![ Span::styled( " Edit Port Range ", - Style::default().fg(VERY_LIGHT_AZURE), + if self.connection_mode == ConnectionMode::CustomPorts { + Style::default().fg(VERY_LIGHT_AZURE) + } else { + Style::default().fg(COOL_GREY) + }, + ), + Span::styled( + " [Ctrl+P] ", + if self.connection_mode == ConnectionMode::CustomPorts { + Style::default().fg(GHOST_WHITE) + } else { + Style::default().fg(COOL_GREY) + }, ), - Span::styled(" [Ctrl+P] ", Style::default().fg(GHOST_WHITE)), ]) .alignment(Alignment::Right), ), diff --git a/node-launchpad/src/components/popup/connection_mode.rs b/node-launchpad/src/components/popup/connection_mode.rs index 9b0c4d3d08..3e0b4b8b8f 100644 --- a/node-launchpad/src/components/popup/connection_mode.rs +++ b/node-launchpad/src/components/popup/connection_mode.rs @@ -132,9 +132,13 @@ impl Component for ChangeConnectionModePopUp { self.connection_mode_selection.connection_mode.clone(), ), Action::OptionsActions(OptionsActions::UpdateConnectionMode( - connection_mode.connection_mode, + connection_mode.clone().connection_mode, )), - Action::SwitchScene(Scene::Options), + if connection_mode.connection_mode == ConnectionMode::CustomPorts { + Action::SwitchScene(Scene::ChangePortsPopUp) + } else { + Action::SwitchScene(Scene::Options) + }, ] } else { debug!("Got Enter, but no new selection. We should not do anything"); diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index e69de29bb2..9ce7ae48f1 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -0,0 +1,341 @@ +// Copyright 2024 MaidSafe.net limited. +// +// This SAFE Network Software is licensed to you under The General Public License (GPL), version 3. +// Unless required by applicable law or agreed to in writing, the SAFE Network Software distributed +// under the GPL Licence is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. Please review the Licences for the specific language governing +// permissions and limitations relating to use of the SAFE Network Software. + +use super::super::utils::centered_rect_fixed; +use super::super::Component; +use crate::{ + action::{Action, OptionsActions}, + connection_mode::ConnectionMode, + mode::{InputMode, Scene}, + style::{clear_area, EUCALYPTUS, GHOST_WHITE, INDIGO, LIGHT_PERIWINKLE, VIVID_SKY_BLUE}, +}; +use color_eyre::Result; +use crossterm::event::{Event, KeyCode, KeyEvent}; +use ratatui::{prelude::*, widgets::*}; +use tui_input::{backend::crossterm::EventHandler, Input}; + +const PORT_MAX: u16 = 65535; +const PORT_MIN: u16 = 1024; +const INPUT_SIZE: u16 = 5; +const INPUT_AREA: u16 = INPUT_SIZE + 2; // +2 for the left and right padding + +#[derive(PartialEq)] +enum FocusInput { + PortFrom, + PortTo, +} + +pub struct PortRangePopUp { + active: bool, + connection_mode: ConnectionMode, + port_from: Input, + port_to: Input, + port_from_old_value: u16, + port_to_old_value: u16, + focus: FocusInput, + can_save: bool, +} + +impl PortRangePopUp { + pub fn new(connection_mode: ConnectionMode, port_from: u16, port_to: u16) -> Self { + Self { + active: false, + connection_mode, + port_from: Input::default().with_value(port_from.to_string()), + port_to: Input::default().with_value(port_to.to_string()), + port_from_old_value: Default::default(), + port_to_old_value: Default::default(), + focus: FocusInput::PortFrom, + can_save: false, + } + } + + pub fn validate(&mut self) { + if self.port_from.value().is_empty() || self.port_to.value().is_empty() { + self.can_save = false; + } else { + let port_from: u16 = self.port_from.value().parse().unwrap_or_default(); + let port_to: u16 = self.port_to.value().parse().unwrap_or_default(); + self.can_save = (PORT_MIN..=PORT_MAX).contains(&port_from) + && (PORT_MIN..=PORT_MAX).contains(&port_to) + && port_from <= port_to; + } + } +} + +impl Component for PortRangePopUp { + fn handle_key_events(&mut self, key: KeyEvent) -> Result> { + if !self.active { + return Ok(vec![]); + } + // while in entry mode, keybinds are not captured, so gotta exit entry mode from here + let send_back = match key.code { + KeyCode::Enter => { + let port_from = self.port_from.value(); + let port_to = self.port_to.value(); + + if port_from.is_empty() || port_to.is_empty() || !self.can_save { + debug!("Got Enter, but port_from or port_to is empty, ignoring."); + return Ok(vec![]); + } + debug!("Got Enter, saving the ports and switching to Options Screen",); + vec![ + Action::StorePortRange( + self.port_from.value().parse().unwrap_or_default(), + self.port_to.value().parse().unwrap_or_default(), + ), + Action::OptionsActions(OptionsActions::UpdatePortRange( + self.port_from.value().parse().unwrap_or_default(), + self.port_to.value().parse().unwrap_or_default(), + )), + Action::SwitchScene(Scene::Options), + ] + } + KeyCode::Esc => { + debug!("Got Esc, restoring the old values and switching to actual screen"); + // reset to old value + self.port_from = self + .port_from + .clone() + .with_value(self.port_from_old_value.to_string()); + self.port_to = self + .port_to + .clone() + .with_value(self.port_to_old_value.to_string()); + vec![Action::SwitchScene(Scene::Options)] + } + KeyCode::Char(c) if !c.is_numeric() => vec![], + KeyCode::Tab => { + self.focus = if self.focus == FocusInput::PortFrom { + FocusInput::PortTo + } else { + FocusInput::PortFrom + }; + vec![] + } + KeyCode::Up => { + if self.focus == FocusInput::PortFrom + && self.port_from.value().parse::().unwrap_or_default() < PORT_MAX + { + self.port_from = self.port_from.clone().with_value( + (self.port_from.value().parse::().unwrap_or_default() + 1).to_string(), + ); + } else if self.focus == FocusInput::PortTo + && self.port_from.value().parse::().unwrap_or_default() > PORT_MIN + { + self.port_to = self.port_to.clone().with_value( + (self.port_to.value().parse::().unwrap_or_default() + 1).to_string(), + ); + } + self.validate(); + vec![] + } + KeyCode::Down => { + if self.focus == FocusInput::PortFrom + && self.port_from.value().parse::().unwrap_or_default() > PORT_MIN + { + self.port_from = self.port_from.clone().with_value( + (self.port_from.value().parse::().unwrap_or_default() - 1).to_string(), + ); + } else if self.focus == FocusInput::PortTo + && self.port_to.value().parse::().unwrap_or_default() < PORT_MAX + { + self.port_to = self.port_to.clone().with_value( + (self.port_to.value().parse::().unwrap_or_default() - 1).to_string(), + ); + } + self.validate(); + vec![] + } + KeyCode::Backspace => { + // if max limit reached, we should allow Backspace to work. + if self.focus == FocusInput::PortFrom { + self.port_from.handle_event(&Event::Key(key)); + } else if self.focus == FocusInput::PortTo { + self.port_to.handle_event(&Event::Key(key)); + } + self.validate(); + vec![] + } + _ => { + // if max limit reached, we should not allow any more inputs. + if self.focus == FocusInput::PortFrom + && self.port_from.value().len() < INPUT_SIZE as usize + { + self.port_from.handle_event(&Event::Key(key)); + } else if self.focus == FocusInput::PortTo + && self.port_to.value().len() < INPUT_SIZE as usize + { + self.port_to.handle_event(&Event::Key(key)); + } + + self.validate(); + vec![] + } + }; + Ok(send_back) + } + + fn update(&mut self, action: Action) -> Result> { + let send_back = match action { + Action::SwitchScene(scene) => match scene { + Scene::ChangePortsPopUp => { + if self.connection_mode == ConnectionMode::CustomPorts { + self.active = true; + self.validate(); + self.port_from_old_value = + self.port_from.value().parse().unwrap_or_default(); + self.port_to_old_value = self.port_to.value().parse().unwrap_or_default(); + // Set to InputMode::Entry as we want to handle everything within our handle_key_events + // so by default if this scene is active, we capture inputs. + Some(Action::SwitchInputMode(InputMode::Entry)) + } else { + self.active = false; + Some(Action::SwitchScene(Scene::Options)) + } + } + _ => { + self.active = false; + None + } + }, + // Useful when the user has selected a connection mode but didn't confirm it + Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { + self.connection_mode = connection_mode; + None + } + _ => None, + }; + Ok(send_back) + } + + fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { + if !self.active { + return Ok(()); + } + + let layer_zero = centered_rect_fixed(52, 15, area); + + let layer_one = Layout::new( + Direction::Vertical, + [ + // for the pop_up_border + Constraint::Length(2), + // for the input field + Constraint::Min(1), + // for the pop_up_border + Constraint::Length(1), + ], + ) + .split(layer_zero); + + // layer zero + let pop_up_border = Paragraph::new("").block( + Block::default() + .borders(Borders::ALL) + .title(" Custom Ports ") + .title_style(Style::new().fg(VIVID_SKY_BLUE)) + .padding(Padding::uniform(2)) + .border_style(Style::new().fg(VIVID_SKY_BLUE)), + ); + clear_area(f, layer_zero); + + // split into 4 parts, for the prompt, input, text, dash , and buttons + let layer_two = Layout::new( + Direction::Vertical, + [ + // for the prompt text + Constraint::Length(3), + // for the input + Constraint::Length(2), + // for the text + Constraint::Length(3), + // gap + Constraint::Length(3), + // for the buttons + Constraint::Length(1), + ], + ) + .split(layer_one[1]); + + let prompt = Paragraph::new("Enter Port Number") + .bold() + .alignment(Alignment::Center); + + f.render_widget(prompt.fg(GHOST_WHITE), layer_two[0]); + + let spaces_from = " ".repeat((INPUT_AREA - 1) as usize - self.port_from.value().len()); + let spaces_to = " ".repeat((INPUT_AREA - 1) as usize - self.port_to.value().len()); + + let input_line = Line::from(vec![ + Span::styled( + format!("{}{} ", spaces_from, self.port_from.value()), + if self.focus == FocusInput::PortFrom { + Style::default() + .fg(VIVID_SKY_BLUE) + .bg(INDIGO) + .underlined() + .underline_color(VIVID_SKY_BLUE) + } else { + Style::default().fg(VIVID_SKY_BLUE) + }, + ), + Span::styled(" to ", Style::default().fg(GHOST_WHITE)), + Span::styled( + format!("{}{} ", spaces_to, self.port_to.value()), + if self.focus == FocusInput::PortTo { + Style::default() + .fg(VIVID_SKY_BLUE) + .bg(INDIGO) + .underlined() + .underline_color(VIVID_SKY_BLUE) + } else { + Style::default().fg(VIVID_SKY_BLUE) + }, + ), + ]) + .alignment(Alignment::Center); + + f.render_widget(input_line, layer_two[1]); + + let text = Paragraph::new("Choose the start of the port range. The range will then match the number of nodes on this device.") + .block(block::Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Center) + .wrap(Wrap { trim: true }); + f.render_widget(text.fg(GHOST_WHITE), layer_two[2]); + + let dash = Block::new() + .borders(Borders::BOTTOM) + .border_style(Style::new().fg(GHOST_WHITE)); + f.render_widget(dash, layer_two[3]); + + let buttons_layer = + Layout::horizontal(vec![Constraint::Percentage(50), Constraint::Percentage(50)]) + .split(layer_two[4]); + + let button_no = Line::from(vec![Span::styled( + " Cancel [Esc]", + Style::default().fg(LIGHT_PERIWINKLE), + )]); + let button_yes_style = if self.can_save { + Style::default().fg(EUCALYPTUS) + } else { + Style::default().fg(LIGHT_PERIWINKLE) + }; + f.render_widget(button_no, buttons_layer[0]); + let button_yes = Line::from(vec![Span::styled( + "Save Port Range [Enter]", + button_yes_style, + )]); + f.render_widget(button_yes, buttons_layer[1]); + + f.render_widget(pop_up_border, layer_zero); + + Ok(()) + } +} diff --git a/node-launchpad/src/connection_mode.rs b/node-launchpad/src/connection_mode.rs index fd8bd1093b..51286d7b0a 100644 --- a/node-launchpad/src/connection_mode.rs +++ b/node-launchpad/src/connection_mode.rs @@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter, Result}; use serde::{Deserialize, Serialize}; use strum::EnumIter; -#[derive(Clone, Debug, Default, EnumIter)] +#[derive(Clone, Debug, Default, EnumIter, Eq, PartialEq)] pub enum ConnectionMode { #[default] Automatic, @@ -23,20 +23,6 @@ impl Display for ConnectionMode { } } -impl PartialEq for ConnectionMode { - fn eq(&self, other: &Self) -> bool { - matches!( - (self, other), - (ConnectionMode::HomeNetwork, ConnectionMode::HomeNetwork) - | (ConnectionMode::UPnP, ConnectionMode::UPnP) - | (ConnectionMode::CustomPorts, ConnectionMode::CustomPorts) - | (ConnectionMode::Automatic, ConnectionMode::Automatic) - ) - } -} - -impl Eq for ConnectionMode {} - impl<'de> Deserialize<'de> for ConnectionMode { fn deserialize(deserializer: D) -> std::result::Result where From 8d563a118b963e8186e111b5007a9a6c639f4745 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 21 Aug 2024 13:55:01 +0200 Subject: [PATCH 11/35] fix(launchpad): updating ports on status screen --- node-launchpad/src/components/status.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 28fb98ce97..23ba727e7b 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -392,6 +392,10 @@ impl Component for Status { Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { self.connection_mode = connection_mode; } + Action::OptionsActions(OptionsActions::UpdatePortRange(port_from, port_to)) => { + self.port_from = Some(port_from); + self.port_to = Some(port_to); + } _ => {} } Ok(None) From 2937f3ec50f09b1b05c003235dde27aa7963a606 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 21 Aug 2024 13:55:28 +0200 Subject: [PATCH 12/35] fix(launchpad): beta programme popups restyling --- .../src/components/popup/beta_programme.rs | 111 ++++++++++++------ 1 file changed, 73 insertions(+), 38 deletions(-) diff --git a/node-launchpad/src/components/popup/beta_programme.rs b/node-launchpad/src/components/popup/beta_programme.rs index 18c8192faa..bcfbe45acd 100644 --- a/node-launchpad/src/components/popup/beta_programme.rs +++ b/node-launchpad/src/components/popup/beta_programme.rs @@ -11,7 +11,7 @@ use super::super::Component; use crate::{ action::{Action, OptionsActions}, mode::{InputMode, Scene}, - style::{clear_area, EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VIVID_SKY_BLUE}, + style::{clear_area, EUCALYPTUS, GHOST_WHITE, INDIGO, LIGHT_PERIWINKLE, VIVID_SKY_BLUE}, widgets::hyperlink::Hyperlink, }; use color_eyre::Result; @@ -19,6 +19,9 @@ use crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::{prelude::*, widgets::*}; use tui_input::{backend::crossterm::EventHandler, Input}; +const INPUT_SIZE_USERNAME: u16 = 32; // as per discord docs +const INPUT_AREA_USERNAME: u16 = INPUT_SIZE_USERNAME + 2; // +2 for the padding + pub struct BetaProgramme { /// Whether the component is active right now, capturing keystrokes + draw things. active: bool, @@ -199,9 +202,9 @@ impl Component for BetaProgramme { // for the prompt text Constraint::Length(3), // for the input - Constraint::Length(3), + Constraint::Length(1), // for the text - Constraint::Length(4), + Constraint::Length(6), // gap Constraint::Length(1), // for the buttons @@ -211,26 +214,24 @@ impl Component for BetaProgramme { .split(layer_one[1]); let prompt_text = Paragraph::new("Discord Username associated with this device:") + .block(Block::default()) .alignment(Alignment::Center) .fg(GHOST_WHITE); f.render_widget(prompt_text, layer_two[0]); - let input = Paragraph::new(self.discord_input_filed.value()) - .alignment(Alignment::Center) - .fg(VIVID_SKY_BLUE); - f.set_cursor( - // Put cursor past the end of the input text - layer_two[1].x - + (layer_two[1].width / 2) as u16 - + (self.discord_input_filed.value().len() / 2) as u16 - + if self.discord_input_filed.value().len() % 2 != 0 { - 1 - } else { - 0 - }, - layer_two[1].y, + let spaces = " ".repeat( + (INPUT_AREA_USERNAME - 1) as usize - self.discord_input_filed.value().len(), ); + let input = Paragraph::new(Span::styled( + format!("{}{} ", spaces, self.discord_input_filed.value()), + Style::default() + .fg(VIVID_SKY_BLUE) + .bg(INDIGO) + .underlined() + .underline_color(VIVID_SKY_BLUE), + )) + .alignment(Alignment::Center); f.render_widget(input, layer_two[1]); let text = Paragraph::new(Text::from(vec![ @@ -238,7 +239,11 @@ impl Component for BetaProgramme { Line::raw("and any Nanos left on this device will be lost."), ])) .alignment(Alignment::Center) - .block(Block::default().padding(Padding::horizontal(2))); + .block( + Block::default() + .padding(Padding::horizontal(2)) + .padding(Padding::top(2)), + ); f.render_widget(text.fg(GHOST_WHITE), layer_two[2]); @@ -276,7 +281,7 @@ impl Component for BetaProgramme { Direction::Vertical, [ // for the text - Constraint::Length(6), + Constraint::Length(7), // for the hypertext Constraint::Length(1), // gap @@ -287,8 +292,18 @@ impl Component for BetaProgramme { ) .split(layer_one[1]); - let text = Paragraph::new(" Earn a slice of millions of tokens created at\n the genesis of the Autonomi Network by running\n nodes to build and test the Beta.\n\n To continue in the beta Rewards Program you\n agree to the Terms and Conditions found here:"); + let text = Paragraph::new(vec![ + Line::from(Span::styled("Earn a slice of millions of tokens created at the genesis of the Autonomi Network by running nodes to build and test the Beta.",Style::default())), + Line::from(Span::styled("\n\n",Style::default())), + Line::from(Span::styled("To continue in the beta Rewards Program you agree to the Terms and Conditions found here:",Style::default())), + Line::from(Span::styled("\n\n",Style::default())), + ] + ) + .block(Block::default().padding(Padding::horizontal(2))) + .wrap(Wrap { trim: false }); + f.render_widget(text.fg(GHOST_WHITE), layer_two[0]); + let link = Hyperlink::new( Span::styled( " https://autonomi.com/beta/terms", @@ -336,7 +351,17 @@ impl Component for BetaProgramme { ) .split(layer_one[1]); - let text = Paragraph::new(" Terms and conditions not accepted\n Beta Rewards Program entry not approved\n You can still run nodes on the network, but\n you will not be part of the Beta Rewards\n Program.\n"); + let text = Paragraph::new(vec![ + Line::from(Span::styled("Terms and conditions not accepted.",Style::default())), + Line::from(Span::styled("\n\n",Style::default())), + Line::from(Span::styled("Beta Rewards Program entry not approved.",Style::default())), + Line::from(Span::styled("\n\n",Style::default())), + Line::from(Span::styled("You can still run nodes on the network, but you will not be part of the Beta Rewards Program.",Style::default())), + ] + ) + .block(Block::default().padding(Padding::horizontal(2))) + .wrap(Wrap { trim: false }); + f.render_widget(text.fg(GHOST_WHITE), layer_two[0]); let dash = Block::new() @@ -359,9 +384,9 @@ impl Component for BetaProgramme { // for the input Constraint::Length(2), // for the text - Constraint::Length(3), + Constraint::Length(5), // gap - Constraint::Length(3), + Constraint::Length(1), // for the buttons Constraint::Length(1), ], @@ -373,24 +398,34 @@ impl Component for BetaProgramme { f.render_widget(prompt.fg(GHOST_WHITE), layer_two[0]); - let input = Paragraph::new(self.discord_input_filed.value()) - .alignment(Alignment::Center) - .fg(VIVID_SKY_BLUE); - f.set_cursor( - // Put cursor past the end of the input text - layer_two[1].x - + (layer_two[1].width / 2) as u16 - + (self.discord_input_filed.value().len() / 2) as u16 - + if self.discord_input_filed.value().len() % 2 != 0 { - 1 - } else { - 0 - }, - layer_two[1].y, + let spaces = " ".repeat( + (INPUT_AREA_USERNAME - 1) as usize - self.discord_input_filed.value().len(), ); + let input = Paragraph::new(Span::styled( + format!("{}{} ", spaces, self.discord_input_filed.value()), + Style::default() + .fg(VIVID_SKY_BLUE) + .bg(INDIGO) + .underlined() + .underline_color(VIVID_SKY_BLUE), + )) + .alignment(Alignment::Center); f.render_widget(input, layer_two[1]); - let text = Paragraph::new(" Submit your username and track your progress on\n our Discord server. Note: your username may be\n different from your display name."); + let text = Paragraph::new(vec![ + Line::from(Span::styled( + "Submit your username and track your progress on our Discord server.", + Style::default(), + )), + Line::from(Span::styled("\n\n", Style::default())), + Line::from(Span::styled( + "Note: your username may be different from your display name.", + Style::default(), + )), + ]) + .block(Block::default().padding(Padding::horizontal(2))) + .wrap(Wrap { trim: false }); + f.render_widget(text.fg(GHOST_WHITE), layer_two[2]); let dash = Block::new() From 95ce3f03062e29c1d29c37b9bb0e8c0d5063a04b Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 21 Aug 2024 17:30:50 +0200 Subject: [PATCH 13/35] feat(launchpad): more items in help screen --- node-launchpad/src/components/help.rs | 55 +++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 8 deletions(-) diff --git a/node-launchpad/src/components/help.rs b/node-launchpad/src/components/help.rs index 5e9b286b42..3bc293ad0a 100644 --- a/node-launchpad/src/components/help.rs +++ b/node-launchpad/src/components/help.rs @@ -49,7 +49,7 @@ impl Component for Help { .constraints(vec![ Constraint::Length(1), Constraint::Min(7), - Constraint::Max(9), + Constraint::Max(13), ]) .split(area); @@ -171,12 +171,12 @@ impl Component for Help { ])), Cell::from(Line::from(vec![ Span::styled("[Ctrl+S] ", Style::default().fg(GHOST_WHITE)), - Span::styled("Start Nodes", Style::default().fg(EUCALYPTUS)), + Span::styled("Start All Nodes", Style::default().fg(EUCALYPTUS)), ])), Cell::from(Line::from(vec![ - Span::styled("[Ctrl+B] ", Style::default().fg(GHOST_WHITE)), + Span::styled("[Ctrl+K] ", Style::default().fg(GHOST_WHITE)), Span::styled( - "Edit Discord Username", + "Switch Connection Mode", Style::default().fg(VERY_LIGHT_AZURE), ), ])), @@ -194,11 +194,14 @@ impl Component for Help { ])), Cell::from(Line::from(vec![ Span::styled("[Ctrl+X] ", Style::default().fg(GHOST_WHITE)), - Span::styled("Stop Nodes", Style::default().fg(EUCALYPTUS)), + Span::styled("Stop All Nodes", Style::default().fg(EUCALYPTUS)), ])), Cell::from(Line::from(vec![ - Span::styled("[Ctrl+L] ", Style::default().fg(GHOST_WHITE)), - Span::styled("Open Logs Folder", Style::default().fg(VERY_LIGHT_AZURE)), + Span::styled("[Ctrl+P] ", Style::default().fg(GHOST_WHITE)), + Span::styled( + "Edit Custom Port Range", + Style::default().fg(VERY_LIGHT_AZURE), + ), ])), ]), Row::new(vec![ @@ -216,7 +219,43 @@ impl Component for Help { Span::styled("[Ctrl+R] ", Style::default().fg(GHOST_WHITE)), Span::styled("Reset All Nodes", Style::default().fg(EUCALYPTUS)), ])), - Cell::from(""), + Cell::from(Line::from(vec![ + Span::styled("[Ctrl+B] ", Style::default().fg(GHOST_WHITE)), + Span::styled( + "Edit Discord Username", + Style::default().fg(VERY_LIGHT_AZURE), + ), + ])), + ]), + Row::new(vec![ + // Empty row for padding + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + ]), + Row::new(vec![ + // Empty row for padding + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + Cell::from(Line::from(vec![ + Span::styled("[Ctrl+L] ", Style::default().fg(GHOST_WHITE)), + Span::styled("Open Logs Folder", Style::default().fg(VERY_LIGHT_AZURE)), + ])), + ]), + Row::new(vec![ + // Empty row for padding + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + ]), + Row::new(vec![ + // Empty row for padding + Cell::from(Span::raw(" ")), + Cell::from(Span::raw(" ")), + Cell::from(Line::from(vec![ + Span::styled("[Ctrl+L] ", Style::default().fg(GHOST_WHITE)), + Span::styled("Open Logs Folder", Style::default().fg(VERY_LIGHT_AZURE)), + ])), ]), ]; From 681bb0db145d6700fe2bd2f24b7e43e692277e77 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 21 Aug 2024 17:31:12 +0200 Subject: [PATCH 14/35] feat(launchpad): reset nodes input styling --- .../src/components/popup/reset_nodes.rs | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/node-launchpad/src/components/popup/reset_nodes.rs b/node-launchpad/src/components/popup/reset_nodes.rs index 7d83ef17bf..220f5e5fca 100644 --- a/node-launchpad/src/components/popup/reset_nodes.rs +++ b/node-launchpad/src/components/popup/reset_nodes.rs @@ -10,13 +10,16 @@ use super::super::{utils::centered_rect_fixed, Component}; use crate::{ action::{Action, OptionsActions}, mode::{InputMode, Scene}, - style::{clear_area, EUCALYPTUS, GHOST_WHITE, LIGHT_PERIWINKLE, VIVID_SKY_BLUE}, + style::{clear_area, EUCALYPTUS, GHOST_WHITE, INDIGO, LIGHT_PERIWINKLE, VIVID_SKY_BLUE}, }; use color_eyre::Result; use crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::{prelude::*, widgets::*}; use tui_input::{backend::crossterm::EventHandler, Input}; +const INPUT_SIZE: u16 = 5; +const INPUT_AREA: u16 = INPUT_SIZE + 2; // +2 for the left and right padding + #[derive(Default)] pub struct ResetNodesPopup { /// Whether the component is active right now, capturing keystrokes + draw things. @@ -56,7 +59,7 @@ impl Component for ResetNodesPopup { } _ => { // max char limit - if self.confirmation_input_field.value().chars().count() < 10 { + if self.confirmation_input_field.value().chars().count() < INPUT_SIZE as usize { self.confirmation_input_field.handle_event(&Event::Key(key)); } vec![] @@ -145,21 +148,19 @@ impl Component for ResetNodesPopup { f.render_widget(prompt, layer_two[0]); - let input = Paragraph::new(self.confirmation_input_field.value()) - .alignment(Alignment::Center) - .fg(VIVID_SKY_BLUE); - f.set_cursor( - // Put cursor past the end of the input text - layer_two[1].x - + (layer_two[1].width / 2) as u16 - + (self.confirmation_input_field.value().len() / 2) as u16 - + if self.confirmation_input_field.value().len() % 2 != 0 { - 1 - } else { - 0 - }, - layer_two[1].y, - ); + let spaces = + " ".repeat((INPUT_AREA - 1) as usize - self.confirmation_input_field.value().len()); + + let input = Paragraph::new(Span::styled( + format!("{}{} ", spaces, self.confirmation_input_field.value()), + Style::default() + .fg(VIVID_SKY_BLUE) + .bg(INDIGO) + .underlined() + .underline_color(VIVID_SKY_BLUE), + )) + .alignment(Alignment::Center); + f.render_widget(input, layer_two[1]); let text = Paragraph::new("This will clear out all the nodes and all the stored data. You should still keep all your earned rewards.") From b5160381cb89c3226b25e2ea9410fb15e574cb47 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 22 Aug 2024 11:52:24 +0200 Subject: [PATCH 15/35] feat(launchpad): better interaction when resetting nodes --- .../src/components/popup/reset_nodes.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/node-launchpad/src/components/popup/reset_nodes.rs b/node-launchpad/src/components/popup/reset_nodes.rs index 220f5e5fca..c021598278 100644 --- a/node-launchpad/src/components/popup/reset_nodes.rs +++ b/node-launchpad/src/components/popup/reset_nodes.rs @@ -25,6 +25,7 @@ pub struct ResetNodesPopup { /// Whether the component is active right now, capturing keystrokes + draw things. active: bool, confirmation_input_field: Input, + can_reset: bool, } impl Component for ResetNodesPopup { @@ -34,17 +35,14 @@ impl Component for ResetNodesPopup { } let send_back = match key.code { KeyCode::Enter => { - let input = self.confirmation_input_field.value().to_string(); - - if input.to_lowercase() == "reset" { + if self.can_reset { debug!("Got reset, sending Reset action and switching to Options"); vec![ Action::OptionsActions(OptionsActions::ResetNodes), Action::SwitchScene(Scene::Options), ] } else { - debug!("Got Enter, but RESET is not typed. Switching to Options"); - vec![Action::SwitchScene(Scene::Options)] + vec![] } } KeyCode::Esc => { @@ -55,6 +53,8 @@ impl Component for ResetNodesPopup { KeyCode::Backspace => { // if max limit reached, we should allow Backspace to work. self.confirmation_input_field.handle_event(&Event::Key(key)); + let input = self.confirmation_input_field.value().to_string(); + self.can_reset = input.to_lowercase() == "reset"; vec![] } _ => { @@ -62,6 +62,8 @@ impl Component for ResetNodesPopup { if self.confirmation_input_field.value().chars().count() < INPUT_SIZE as usize { self.confirmation_input_field.handle_event(&Event::Key(key)); } + let input = self.confirmation_input_field.value().to_string(); + self.can_reset = input.to_lowercase() == "reset"; vec![] } }; @@ -193,7 +195,11 @@ impl Component for ResetNodesPopup { let button_yes = Line::from(vec![Span::styled( "Reset Nodes [Enter]", - Style::default().fg(EUCALYPTUS), + if self.can_reset { + Style::default().fg(EUCALYPTUS) + } else { + Style::default().fg(LIGHT_PERIWINKLE) + }, )]) .alignment(Alignment::Right); From 9a16c52916bc6a073f18c7a94040c46b4a41a7a4 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 22 Aug 2024 11:53:10 +0200 Subject: [PATCH 16/35] feat(launchpad): connection modes integration with service --- node-launchpad/src/app.rs | 16 +- node-launchpad/src/components/status.rs | 231 ++++++++++++++---------- node-launchpad/src/node_mgmt.rs | 102 ++++++++--- 3 files changed, 218 insertions(+), 131 deletions(-) diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index c0621eda10..668f308308 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -18,6 +18,7 @@ use crate::{ connection_mode::ChangeConnectionModePopUp, manage_nodes::ManageNodes, port_range::PortRangePopUp, reset_nodes::ResetNodesPopup, }, + status::{Status, StatusConfig}, Component, }, config::{get_launchpad_nodes_data_dir_path, AppData, Config}, @@ -87,17 +88,18 @@ impl App { .unwrap_or(get_primary_mount_point_name()?); // Main Screens - let status = Status::new( - app_data.nodes_to_start, - &app_data.discord_username, + let status_config = StatusConfig { + allocated_disk_space: app_data.nodes_to_start, + discord_username: app_data.discord_username.clone(), peers_args, safenode_path, data_dir_path, connection_mode, - Some(port_from), - Some(port_to), - ) - .await?; + port_from: Some(port_from), + port_to: Some(port_to), + }; + + let status = Status::new(status_config).await?; let options = Options::new( storage_mountpoint.clone(), storage_drive.clone(), diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 23ba727e7b..cb316fa2da 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -15,6 +15,7 @@ use super::{ use crate::action::OptionsActions; use crate::config::get_launchpad_nodes_data_dir_path; use crate::connection_mode::ConnectionMode; +use crate::node_mgmt::MaintainNodesArgs; use crate::{ action::{Action, StatusActions}, config::Config, @@ -28,6 +29,7 @@ use color_eyre::eyre::{OptionExt, Result}; use crossterm::event::KeyEvent; use ratatui::text::Span; use ratatui::{prelude::*, widgets::*}; +use sn_node_manager::add_services::config::PortRange; use sn_node_manager::config::get_node_registry_path; use sn_peers_acquisition::PeersArgs; use sn_service_management::{ @@ -85,19 +87,21 @@ pub enum LockRegistryState { ResettingNodes, } +pub struct StatusConfig { + pub allocated_disk_space: usize, + pub discord_username: String, + pub peers_args: PeersArgs, + pub safenode_path: Option, + pub data_dir_path: PathBuf, + pub connection_mode: ConnectionMode, + pub port_from: Option, + pub port_to: Option, +} + impl Status { - pub async fn new( - allocated_disk_space: usize, - discord_username: &str, - peers_args: PeersArgs, - safenode_path: Option, - data_dir_path: PathBuf, - connection_mode: ConnectionMode, - port_from: Option, - port_to: Option, - ) -> Result { + pub async fn new(config: StatusConfig) -> Result { let mut status = Self { - peers_args, + peers_args: config.peers_args, action_sender: Default::default(), config: Default::default(), active: true, @@ -106,15 +110,15 @@ impl Status { error_while_running_nat_detection: 0, node_stats: NodeStats::default(), node_stats_last_update: Instant::now(), - nodes_to_start: allocated_disk_space, + nodes_to_start: config.allocated_disk_space, node_table_state: Default::default(), lock_registry: None, - discord_username: discord_username.to_string(), - safenode_path, - data_dir_path, - connection_mode, - port_from, - port_to, + discord_username: config.discord_username, + safenode_path: config.safenode_path, + data_dir_path: config.data_dir_path, + connection_mode: config.connection_mode, + port_from: config.port_from, + port_to: config.port_to, }; let now = Instant::now(); @@ -283,100 +287,136 @@ impl Component for Status { if we_have_nodes && has_changed { self.lock_registry = Some(LockRegistryState::ResettingNodes); - info!("Resetting safenode services because the discord username was reset."); + info!("Resetting safenode services because the Discord Username was reset."); let action_sender = self.get_actions_sender()?; reset_nodes(action_sender, true); } } Action::StoreStorageDrive(ref drive_mountpoint, ref _drive_name) => { + self.lock_registry = Some(LockRegistryState::ResettingNodes); + info!("Resetting safenode services because the Storage Drive was changed."); let action_sender = self.get_actions_sender()?; reset_nodes(action_sender, false); self.data_dir_path = get_launchpad_nodes_data_dir_path(&drive_mountpoint.to_path_buf(), false)?; } - Action::StatusActions(status_action) => { - match status_action { - StatusActions::NodesStatsObtained(stats) => { - self.node_stats = stats; - } - StatusActions::StartNodesCompleted | StatusActions::StopNodesCompleted => { - self.lock_registry = None; - self.load_node_registry_and_update_states()?; - } - StatusActions::ResetNodesCompleted { trigger_start_node } => { - self.lock_registry = None; - self.load_node_registry_and_update_states()?; + Action::StoreConnectionMode(connection_mode) => { + self.connection_mode = connection_mode; + self.lock_registry = Some(LockRegistryState::ResettingNodes); + info!("Resetting safenode services because the Connection Mode range was changed."); + let action_sender = self.get_actions_sender()?; + reset_nodes(action_sender, false); + } + Action::StorePortRange(port_from, port_range) => { + self.port_from = Some(port_from); + self.port_to = Some(port_range); + self.lock_registry = Some(LockRegistryState::ResettingNodes); + info!("Resetting safenode services because the Port Range was changed."); + let action_sender = self.get_actions_sender()?; + reset_nodes(action_sender, false); + } + Action::StatusActions(status_action) => match status_action { + StatusActions::NodesStatsObtained(stats) => { + self.node_stats = stats; + } + StatusActions::StartNodesCompleted | StatusActions::StopNodesCompleted => { + self.lock_registry = None; + self.load_node_registry_and_update_states()?; + } + StatusActions::ResetNodesCompleted { trigger_start_node } => { + self.lock_registry = None; + self.load_node_registry_and_update_states()?; - if trigger_start_node { - debug!("Reset nodes completed. Triggering start nodes."); - return Ok(Some(Action::StatusActions(StatusActions::StartNodes))); - } - debug!("Reset nodes completed"); - } - StatusActions::SuccessfullyDetectedNatStatus => { - debug!("Successfully detected nat status, is_nat_status_determined set to true"); - self.is_nat_status_determined = true; - } - StatusActions::ErrorWhileRunningNatDetection => { - self.error_while_running_nat_detection += 1; - debug!( - "Error while running nat detection. Error count: {}", - self.error_while_running_nat_detection - ); - } - StatusActions::TriggerManageNodes => { - return Ok(Some(Action::SwitchScene(Scene::ManageNodesPopUp))); - } - StatusActions::PreviousTableItem => { - self.select_previous_table_item(); + if trigger_start_node { + debug!("Reset nodes completed. Triggering start nodes."); + return Ok(Some(Action::StatusActions(StatusActions::StartNodes))); } - StatusActions::NextTableItem => { - self.select_next_table_item(); + debug!("Reset nodes completed"); + } + StatusActions::SuccessfullyDetectedNatStatus => { + debug!( + "Successfully detected nat status, is_nat_status_determined set to true" + ); + self.is_nat_status_determined = true; + } + StatusActions::ErrorWhileRunningNatDetection => { + self.error_while_running_nat_detection += 1; + debug!( + "Error while running nat detection. Error count: {}", + self.error_while_running_nat_detection + ); + } + StatusActions::TriggerManageNodes => { + return Ok(Some(Action::SwitchScene(Scene::ManageNodesPopUp))); + } + StatusActions::PreviousTableItem => { + self.select_previous_table_item(); + } + StatusActions::NextTableItem => { + self.select_next_table_item(); + } + StatusActions::StartNodes => { + debug!("Got action to start nodes"); + if self.lock_registry.is_some() { + error!("Registry is locked. Cannot start node now."); + return Ok(None); } - StatusActions::StartNodes => { - debug!("Got action to start nodes"); - if self.lock_registry.is_some() { - error!("Registry is locked. Cannot start node now."); - return Ok(None); - } - if self.nodes_to_start == 0 { - info!("Nodes to start not set. Ask for input."); - return Ok(Some(Action::StatusActions( - StatusActions::TriggerManageNodes, - ))); - } - - self.lock_registry = Some(LockRegistryState::StartingNodes); - let action_sender = self.get_actions_sender()?; - info!("Running maintain node count: {:?}", self.nodes_to_start); - - maintain_n_running_nodes( - self.nodes_to_start as u16, - self.discord_username.clone(), - self.peers_args.clone(), - self.should_we_run_nat_detection(), - self.safenode_path.clone(), - Some(self.data_dir_path.clone()), - action_sender, - ); + if self.nodes_to_start == 0 { + info!("Nodes to start not set. Ask for input."); + return Ok(Some(Action::StatusActions( + StatusActions::TriggerManageNodes, + ))); } - StatusActions::StopNodes => { - debug!("Got action to stop nodes"); - if self.lock_registry.is_some() { - error!("Registry is locked. Cannot stop node now."); + + self.lock_registry = Some(LockRegistryState::StartingNodes); + let action_sender = self.get_actions_sender()?; + info!("Running maintain node count: {:?}", self.nodes_to_start); + + let port_range_str = format!( + "{}-{}", + self.port_from.unwrap_or(0), + self.port_to.unwrap_or(0) + ); + + let port_range = match PortRange::parse(&port_range_str) { + Ok(port_range) => port_range, + Err(err) => { + error!("When starting nodes, we got an error while parsing port range: {err:?}"); return Ok(None); } + }; + + let maintain_nodes_args = MaintainNodesArgs { + count: self.nodes_to_start as u16, + owner: self.discord_username.clone(), + peers_args: self.peers_args.clone(), + run_nat_detection: self.should_we_run_nat_detection() + && self.connection_mode == ConnectionMode::Automatic, + safenode_path: self.safenode_path.clone(), + data_dir_path: Some(self.data_dir_path.clone()), + action_sender, + connection_mode: self.connection_mode.clone(), + port_range: Some(port_range), + }; + + maintain_n_running_nodes(maintain_nodes_args); + } + StatusActions::StopNodes => { + debug!("Got action to stop nodes"); + if self.lock_registry.is_some() { + error!("Registry is locked. Cannot stop node now."); + return Ok(None); + } - let running_nodes = self.get_running_nodes(); - self.lock_registry = Some(LockRegistryState::StoppingNodes); - let action_sender = self.get_actions_sender()?; - info!("Stopping node service: {running_nodes:?}"); + let running_nodes = self.get_running_nodes(); + self.lock_registry = Some(LockRegistryState::StoppingNodes); + let action_sender = self.get_actions_sender()?; + info!("Stopping node service: {running_nodes:?}"); - stop_nodes(running_nodes, action_sender); - } + stop_nodes(running_nodes, action_sender); } - } + }, Action::OptionsActions(OptionsActions::ResetNodes) => { debug!("Got action to reset nodes"); if self.lock_registry.is_some() { @@ -389,13 +429,6 @@ impl Component for Status { info!("Got action to reset nodes"); reset_nodes(action_sender, false); } - Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { - self.connection_mode = connection_mode; - } - Action::OptionsActions(OptionsActions::UpdatePortRange(port_from, port_to)) => { - self.port_from = Some(port_from); - self.port_to = Some(port_to); - } _ => {} } Ok(None) diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index 1bfe76588b..f3c81b4de4 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -1,12 +1,14 @@ use std::path::PathBuf; -use sn_node_manager::VerbosityLevel; +use sn_node_manager::{add_services::config::PortRange, VerbosityLevel}; use sn_peers_acquisition::PeersArgs; use tokio::sync::mpsc::UnboundedSender; use crate::action::{Action, StatusActions}; use color_eyre::eyre::Result; +use crate::connection_mode::ConnectionMode; + pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) { tokio::task::spawn_local(async move { if let Err(err) = @@ -24,20 +26,25 @@ pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) }); } -pub fn maintain_n_running_nodes( - count: u16, - owner: String, - peers_args: PeersArgs, - run_nat_detection: bool, - safenode_path: Option, - data_dir_path: Option, - action_sender: UnboundedSender, -) { +pub struct MaintainNodesArgs { + pub count: u16, + pub owner: String, + pub peers_args: PeersArgs, + pub run_nat_detection: bool, + pub safenode_path: Option, + pub data_dir_path: Option, + pub action_sender: UnboundedSender, + pub connection_mode: ConnectionMode, + pub port_range: Option, +} + +pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { tokio::task::spawn_local(async move { - if run_nat_detection { + if args.run_nat_detection { + info!("Running nat detection...."); if let Err(err) = run_nat_detection_process().await { error!("Error while running nat detection {err:?}. Registering the error."); - if let Err(err) = action_sender.send(Action::StatusActions( + if let Err(err) = args.action_sender.send(Action::StatusActions( StatusActions::ErrorWhileRunningNatDetection, )) { error!("Error while sending action: {err:?}"); @@ -47,28 +54,69 @@ pub fn maintain_n_running_nodes( } } - let owner = if owner.is_empty() { None } else { Some(owner) }; + let auto_set_nat_flags: bool = args.connection_mode == ConnectionMode::Automatic; + let upnp: bool = args.connection_mode == ConnectionMode::UPnP; + let home_network: bool = args.connection_mode == ConnectionMode::HomeNetwork; + let custom_ports: Option = if args.connection_mode == ConnectionMode::CustomPorts + { + match args.port_range { + Some(port_range) => { + debug!("Port range to run nodes: {port_range:?}"); + Some(port_range) + } + None => { + debug!("Port range not provided. Using default port range."); + None + } + } + } else { + None + }; + let owner = if args.owner.is_empty() { + None + } else { + Some(args.owner) + }; + + debug!("************"); + debug!( + "Maintaining {} running nodes with the following args:", + args.count + ); + debug!( + " owner: {:?}, peers_args: {:?}, safenode_path: {:?}", + owner, args.peers_args, args.safenode_path + ); + debug!( + " data_dir_path: {:?}, connection_mode: {:?}", + args.data_dir_path, args.connection_mode + ); + debug!( + " auto_set_nat_flags: {:?}, custom_ports: {:?}, upnp: {}, home_network: {}", + auto_set_nat_flags, custom_ports, upnp, home_network + ); + if let Err(err) = sn_node_manager::cmd::node::maintain_n_running_nodes( false, - true, + auto_set_nat_flags, 120, - count, - data_dir_path, + args.count, + args.data_dir_path, true, None, + home_network, false, - false, - None, None, None, None, + custom_ports, owner, - peers_args, + args.peers_args, None, None, - safenode_path, + args.safenode_path, None, - false, + upnp, None, None, VerbosityLevel::Minimal, @@ -76,12 +124,16 @@ pub fn maintain_n_running_nodes( ) .await { - error!("Error while maintaining {count:?} running nodes {err:?}"); + error!( + "Error while maintaining {:?} running nodes {err:?}", + args.count + ); } else { - info!("Maintained {count} running nodes successfully."); + info!("Maintained {} running nodes successfully.", args.count); } - if let Err(err) = - action_sender.send(Action::StatusActions(StatusActions::StartNodesCompleted)) + if let Err(err) = args + .action_sender + .send(Action::StatusActions(StatusActions::StartNodesCompleted)) { error!("Error while sending action: {err:?}"); } From 84e8e728bd645861b5d50cc57dc2bb159edd45dd Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 22 Aug 2024 16:44:26 +0200 Subject: [PATCH 17/35] feat(launchpad): port selection and execution of nodes --- node-launchpad/src/action.rs | 4 +- node-launchpad/src/components/options.rs | 8 +- .../src/components/popup/port_range.rs | 131 +++++++----------- node-launchpad/src/components/status.rs | 31 +++-- node-launchpad/src/config.rs | 4 +- 5 files changed, 78 insertions(+), 100 deletions(-) diff --git a/node-launchpad/src/action.rs b/node-launchpad/src/action.rs index 043089c842..8ab87cf0eb 100644 --- a/node-launchpad/src/action.rs +++ b/node-launchpad/src/action.rs @@ -25,7 +25,7 @@ pub enum Action { StoreStorageDrive(PathBuf, String), StoreConnectionMode(ConnectionMode), - StorePortRange(u16, u16), + StorePortRange(u32, u32), StoreDiscordUserName(String), StoreNodesToStart(usize), @@ -70,7 +70,7 @@ pub enum OptionsActions { TriggerResetNodes, TriggerAccessLogs, UpdateConnectionMode(ConnectionMode), - UpdatePortRange(u16, u16), + UpdatePortRange(u32, u32), UpdateBetaProgrammeUsername(String), UpdateStorageDrive(PathBuf, String), } diff --git a/node-launchpad/src/components/options.rs b/node-launchpad/src/components/options.rs index cf5b8f5f3f..d2605f1759 100644 --- a/node-launchpad/src/components/options.rs +++ b/node-launchpad/src/components/options.rs @@ -31,8 +31,8 @@ pub struct Options { pub discord_username: String, pub connection_mode: ConnectionMode, pub port_edit: bool, - pub port_from: Option, - pub port_to: Option, + pub port_from: Option, + pub port_to: Option, pub active: bool, pub action_tx: Option>, } @@ -43,8 +43,8 @@ impl Options { storage_drive: String, discord_username: String, connection_mode: ConnectionMode, - port_from: Option, - port_to: Option, + port_from: Option, + port_to: Option, ) -> Result { Ok(Self { storage_mountpoint, diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index 9ce7ae48f1..9b44116a08 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -19,30 +19,24 @@ use crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::{prelude::*, widgets::*}; use tui_input::{backend::crossterm::EventHandler, Input}; -const PORT_MAX: u16 = 65535; -const PORT_MIN: u16 = 1024; -const INPUT_SIZE: u16 = 5; -const INPUT_AREA: u16 = INPUT_SIZE + 2; // +2 for the left and right padding - -#[derive(PartialEq)] -enum FocusInput { - PortFrom, - PortTo, -} +pub const PORT_MAX: u32 = 65535; +pub const PORT_MIN: u32 = 1024; +pub const PORT_ALLOCATION: u32 = 49; // We count the port_from as well +const INPUT_SIZE: u32 = 5; +const INPUT_AREA: u32 = INPUT_SIZE + 2; // +2 for the left and right padding pub struct PortRangePopUp { active: bool, connection_mode: ConnectionMode, port_from: Input, port_to: Input, - port_from_old_value: u16, - port_to_old_value: u16, - focus: FocusInput, + port_from_old_value: u32, + port_to_old_value: u32, can_save: bool, } impl PortRangePopUp { - pub fn new(connection_mode: ConnectionMode, port_from: u16, port_to: u16) -> Self { + pub fn new(connection_mode: ConnectionMode, port_from: u32, port_to: u32) -> Self { Self { active: false, connection_mode, @@ -50,17 +44,16 @@ impl PortRangePopUp { port_to: Input::default().with_value(port_to.to_string()), port_from_old_value: Default::default(), port_to_old_value: Default::default(), - focus: FocusInput::PortFrom, can_save: false, } } pub fn validate(&mut self) { - if self.port_from.value().is_empty() || self.port_to.value().is_empty() { + if self.port_from.value().is_empty() { self.can_save = false; } else { - let port_from: u16 = self.port_from.value().parse().unwrap_or_default(); - let port_to: u16 = self.port_to.value().parse().unwrap_or_default(); + let port_from: u32 = self.port_from.value().parse().unwrap_or_default(); + let port_to: u32 = self.port_to.value().parse().unwrap_or_default(); self.can_save = (PORT_MIN..=PORT_MAX).contains(&port_from) && (PORT_MIN..=PORT_MAX).contains(&port_to) && port_from <= port_to; @@ -110,70 +103,58 @@ impl Component for PortRangePopUp { vec![Action::SwitchScene(Scene::Options)] } KeyCode::Char(c) if !c.is_numeric() => vec![], - KeyCode::Tab => { - self.focus = if self.focus == FocusInput::PortFrom { - FocusInput::PortTo - } else { - FocusInput::PortFrom - }; - vec![] - } KeyCode::Up => { - if self.focus == FocusInput::PortFrom - && self.port_from.value().parse::().unwrap_or_default() < PORT_MAX - { + if self.port_from.value().parse::().unwrap_or_default() < PORT_MAX { self.port_from = self.port_from.clone().with_value( - (self.port_from.value().parse::().unwrap_or_default() + 1).to_string(), - ); - } else if self.focus == FocusInput::PortTo - && self.port_from.value().parse::().unwrap_or_default() > PORT_MIN - { - self.port_to = self.port_to.clone().with_value( - (self.port_to.value().parse::().unwrap_or_default() + 1).to_string(), + (self.port_from.value().parse::().unwrap_or_default() + 1).to_string(), ); - } + let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); + if port_from_value + PORT_ALLOCATION <= PORT_MAX { + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + } else { + self.port_to = Input::default().with_value("-".to_string()); + } + }; self.validate(); vec![] } KeyCode::Down => { - if self.focus == FocusInput::PortFrom - && self.port_from.value().parse::().unwrap_or_default() > PORT_MIN - { + if self.port_from.value().parse::().unwrap_or_default() > 0 { self.port_from = self.port_from.clone().with_value( - (self.port_from.value().parse::().unwrap_or_default() - 1).to_string(), - ); - } else if self.focus == FocusInput::PortTo - && self.port_to.value().parse::().unwrap_or_default() < PORT_MAX - { - self.port_to = self.port_to.clone().with_value( - (self.port_to.value().parse::().unwrap_or_default() - 1).to_string(), + (self.port_from.value().parse::().unwrap_or_default() - 1).to_string(), ); - } + let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); + if port_from_value + PORT_ALLOCATION <= PORT_MAX { + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + } else { + self.port_to = Input::default().with_value("-".to_string()); + } + }; self.validate(); vec![] } KeyCode::Backspace => { - // if max limit reached, we should allow Backspace to work. - if self.focus == FocusInput::PortFrom { - self.port_from.handle_event(&Event::Key(key)); - } else if self.focus == FocusInput::PortTo { - self.port_to.handle_event(&Event::Key(key)); - } + self.port_from.handle_event(&Event::Key(key)); + let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); + self.port_to = + Input::default().with_value((port_from_value + PORT_ALLOCATION).to_string()); self.validate(); vec![] } _ => { // if max limit reached, we should not allow any more inputs. - if self.focus == FocusInput::PortFrom - && self.port_from.value().len() < INPUT_SIZE as usize - { + if self.port_from.value().len() < INPUT_SIZE as usize { self.port_from.handle_event(&Event::Key(key)); - } else if self.focus == FocusInput::PortTo - && self.port_to.value().len() < INPUT_SIZE as usize - { - self.port_to.handle_event(&Event::Key(key)); - } - + let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); + if port_from_value + PORT_ALLOCATION <= PORT_MAX { + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + } else { + self.port_to = Input::default().with_value("-".to_string()); + } + }; self.validate(); vec![] } @@ -275,28 +256,16 @@ impl Component for PortRangePopUp { let input_line = Line::from(vec![ Span::styled( format!("{}{} ", spaces_from, self.port_from.value()), - if self.focus == FocusInput::PortFrom { - Style::default() - .fg(VIVID_SKY_BLUE) - .bg(INDIGO) - .underlined() - .underline_color(VIVID_SKY_BLUE) - } else { - Style::default().fg(VIVID_SKY_BLUE) - }, + Style::default() + .fg(VIVID_SKY_BLUE) + .bg(INDIGO) + .underlined() + .underline_color(VIVID_SKY_BLUE), ), Span::styled(" to ", Style::default().fg(GHOST_WHITE)), Span::styled( format!("{}{} ", spaces_to, self.port_to.value()), - if self.focus == FocusInput::PortTo { - Style::default() - .fg(VIVID_SKY_BLUE) - .bg(INDIGO) - .underlined() - .underline_color(VIVID_SKY_BLUE) - } else { - Style::default().fg(VIVID_SKY_BLUE) - }, + Style::default().fg(VIVID_SKY_BLUE), ), ]) .alignment(Alignment::Center); diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index cb316fa2da..2f6bdf4824 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -13,6 +13,7 @@ use super::{ Component, Frame, }; use crate::action::OptionsActions; +use crate::components::popup::port_range::{PORT_ALLOCATION, PORT_MAX, PORT_MIN}; use crate::config::get_launchpad_nodes_data_dir_path; use crate::connection_mode::ConnectionMode; use crate::node_mgmt::MaintainNodesArgs; @@ -75,9 +76,9 @@ pub struct Status { // Connection mode connection_mode: ConnectionMode, // Port from - port_from: Option, + port_from: Option, // Port to - port_to: Option, + port_to: Option, } #[derive(Clone)] @@ -94,8 +95,8 @@ pub struct StatusConfig { pub safenode_path: Option, pub data_dir_path: PathBuf, pub connection_mode: ConnectionMode, - pub port_from: Option, - pub port_to: Option, + pub port_from: Option, + pub port_to: Option, } impl Status { @@ -369,16 +370,23 @@ impl Component for Status { ))); } - self.lock_registry = Some(LockRegistryState::StartingNodes); - let action_sender = self.get_actions_sender()?; - info!("Running maintain node count: {:?}", self.nodes_to_start); + // Check if the port range is valid and we shorten the range based on the nodes to start + if self.port_from.unwrap_or(PORT_MIN) + self.nodes_to_start as u32 > PORT_MAX { + error!("Port range exceeds maximum port number. Cannot start nodes."); + //TODO: Give feedback to the user + return Ok(None); + } let port_range_str = format!( "{}-{}", - self.port_from.unwrap_or(0), - self.port_to.unwrap_or(0) + self.port_from.unwrap_or(PORT_MIN), + self.port_from.unwrap_or(PORT_MIN) - 1 + self.nodes_to_start as u32 ); + self.lock_registry = Some(LockRegistryState::StartingNodes); + let action_sender = self.get_actions_sender()?; + info!("Running maintain node count: {:?}", self.nodes_to_start); + let port_range = match PortRange::parse(&port_range_str) { Ok(port_range) => port_range, Err(err) => { @@ -400,6 +408,7 @@ impl Component for Status { port_range: Some(port_range), }; + //TODO: Handle errors and give feedback to the user maintain_n_running_nodes(maintain_nodes_args); } StatusActions::StopNodes => { @@ -512,8 +521,8 @@ impl Component for Status { ConnectionMode::UPnP => "UPnP", ConnectionMode::CustomPorts => &format!( "Custom Ports {}-{}", - self.port_from.unwrap_or(0), - self.port_to.unwrap_or(0) + self.port_from.unwrap_or(PORT_MIN), + self.port_to.unwrap_or(PORT_MIN + PORT_ALLOCATION) ), ConnectionMode::Automatic => "Automatic", }; diff --git a/node-launchpad/src/config.rs b/node-launchpad/src/config.rs index 1b19ab96e2..59dfe3a975 100644 --- a/node-launchpad/src/config.rs +++ b/node-launchpad/src/config.rs @@ -106,8 +106,8 @@ pub struct AppData { pub storage_mountpoint: Option, pub storage_drive: Option, pub connection_mode: Option, - pub port_from: Option, - pub port_to: Option, + pub port_from: Option, + pub port_to: Option, } impl Default for AppData { From 23abef2dd03a33fd0c96024409db643f0a0bdf38 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 22 Aug 2024 18:06:33 +0200 Subject: [PATCH 18/35] fix(launchpad): configuration for one node one port --- node-launchpad/src/components/status.rs | 30 ++++++++++++++++--------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 2f6bdf4824..56a1207c86 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -370,22 +370,25 @@ impl Component for Status { ))); } + // Port calculation // Check if the port range is valid and we shorten the range based on the nodes to start - if self.port_from.unwrap_or(PORT_MIN) + self.nodes_to_start as u32 > PORT_MAX { + if self.port_from.unwrap_or(PORT_MIN) - 1 + self.nodes_to_start as u32 + > PORT_MAX + { error!("Port range exceeds maximum port number. Cannot start nodes."); //TODO: Give feedback to the user return Ok(None); } - let port_range_str = format!( - "{}-{}", - self.port_from.unwrap_or(PORT_MIN), - self.port_from.unwrap_or(PORT_MIN) - 1 + self.nodes_to_start as u32 - ); - - self.lock_registry = Some(LockRegistryState::StartingNodes); - let action_sender = self.get_actions_sender()?; - info!("Running maintain node count: {:?}", self.nodes_to_start); + let port_range_str = if self.nodes_to_start > 1 { + format!( + "{}-{}", + self.port_from.unwrap_or(PORT_MIN), + self.port_from.unwrap_or(PORT_MIN) - 1 + self.nodes_to_start as u32 + ) + } else { + format!("{}", self.port_from.unwrap_or(PORT_MIN)) + }; let port_range = match PortRange::parse(&port_range_str) { Ok(port_range) => port_range, @@ -395,6 +398,10 @@ impl Component for Status { } }; + self.lock_registry = Some(LockRegistryState::StartingNodes); + let action_sender = self.get_actions_sender()?; + info!("Running maintain node count: {:?}", self.nodes_to_start); + let maintain_nodes_args = MaintainNodesArgs { count: self.nodes_to_start as u16, owner: self.discord_username.clone(), @@ -403,12 +410,13 @@ impl Component for Status { && self.connection_mode == ConnectionMode::Automatic, safenode_path: self.safenode_path.clone(), data_dir_path: Some(self.data_dir_path.clone()), - action_sender, + action_sender: action_sender.clone(), connection_mode: self.connection_mode.clone(), port_range: Some(port_range), }; //TODO: Handle errors and give feedback to the user + stop_nodes(self.get_running_nodes(), action_sender.clone()); maintain_n_running_nodes(maintain_nodes_args); } StatusActions::StopNodes => { From b4e689c1123b2cca12b5d6f0e201889fc78bf210 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 28 Aug 2024 10:09:43 +0200 Subject: [PATCH 19/35] feat(launchpad): error component --- node-launchpad/src/error.rs | 195 ++++++++++++++++++++++++++++++++++++ node-launchpad/src/lib.rs | 1 + node-launchpad/src/style.rs | 1 + 3 files changed, 197 insertions(+) create mode 100644 node-launchpad/src/error.rs diff --git a/node-launchpad/src/error.rs b/node-launchpad/src/error.rs new file mode 100644 index 0000000000..352bbfa8fd --- /dev/null +++ b/node-launchpad/src/error.rs @@ -0,0 +1,195 @@ +use crate::{ + components::utils::centered_rect_fixed, + style::{clear_area, EUCALYPTUS, GHOST_WHITE, RED}, + tui::Frame, +}; +use crossterm::event::{KeyCode, KeyEvent}; +use ratatui::{ + layout::{Alignment, Constraint, Direction, Layout, Rect}, + style::{Style, Stylize}, + text::{Line, Span}, + widgets::{Block, Borders, Padding, Paragraph, Wrap}, +}; + +/// Error popup is a popup that is used to display error messages to the user. +/// +/// It accepts a title, a message and a error message. +/// Handles key events to hide the popup (Enter and Esc keys). +/// +/// How to use: +/// 1. Create a new ErrorPopup member in your component. +/// 2. Show the error popup by calling the `show` method. +/// 3. Hide the error popup by calling the `hide` method. +/// 4. Check if the error popup is visible by calling the `is_visible` method. +/// 5. Draw the error popup by calling the `draw_error` method in your `draw` function. +/// 6. Handle the input for the error popup by calling the `handle_input` method. +/// +/// Example: +/// ```rust +/// use crate::error::ErrorPopup; +/// +/// pub struct MyComponent { +/// error_popup: Option, +/// } +/// +/// impl MyComponent { +/// pub fn new() -> Self { +/// Self { +/// error_popup: None, +/// } +/// } +/// } +/// +/// impl Component for MyComponent { +/// fn handle_key_events(&mut self, key: KeyEvent) -> Result> { +/// if let Some(error_popup) = &mut self.error_popup { +/// if error_popup.is_visible() { +/// error_popup.handle_input(key); +/// return Ok(vec![]); +/// } +/// } +/// // ... Your keys being handled here ... +/// } +/// fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { +/// if let Some(error_popup) = &self.error_popup { +/// if error_popup.is_visible() { +/// error_popup.draw_error(f, area); +/// return Ok(()); +/// } +/// } +/// // ... Your drawing code here ... +/// } +/// } +/// ``` +/// +/// How to trigger the error +/// +/// ```rust +/// self.error_popup = Some(ErrorPopup::new( +/// "Error".to_string(), +/// "This is a test error message".to_string(), +/// "raw message".to_string(), +/// )); +/// if let Some(error_popup) = &mut self.error_popup { +/// error_popup.show(); +/// } +/// ``` + +pub struct ErrorPopup { + visible: bool, + title: String, + message: String, + error_message: String, +} + +impl ErrorPopup { + pub fn new(title: String, message: String, error_message: String) -> Self { + Self { + visible: false, + title, + message, + error_message, + } + } + + pub fn draw_error(&self, f: &mut Frame, area: Rect) { + if !self.visible { + return; + } + + let layer_zero = centered_rect_fixed(52, 15, area); + + let layer_one = Layout::new( + Direction::Vertical, + [ + // for the pop_up_border + padding + Constraint::Length(2), + // for the text + Constraint::Min(1), + // for the pop_up_border + Constraint::Length(1), + ], + ) + .split(layer_zero); + + let pop_up_border = Paragraph::new("").block( + Block::default() + .borders(Borders::ALL) + .title(format!(" {} ", self.title)) + .title_style(Style::new().fg(RED)) + .padding(Padding::uniform(2)) + .border_style(Style::new().fg(RED)), + ); + clear_area(f, layer_zero); + + let layer_two = Layout::new( + Direction::Vertical, + [ + // for the message + Constraint::Length(5), + // for the error_message + Constraint::Length(5), + // gap + Constraint::Length(1), + // for the buttons + Constraint::Length(1), + ], + ) + .split(layer_one[1]); + + let prompt = Paragraph::new(self.message.clone()) + .block(Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Center) + .wrap(Wrap { trim: true }); + + f.render_widget(prompt.fg(GHOST_WHITE), layer_two[0]); + + let text = Paragraph::new(self.error_message.clone()) + .block(Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Center) + .wrap(Wrap { trim: true }); + f.render_widget(text.fg(GHOST_WHITE), layer_two[1]); + + let dash = Block::new() + .borders(Borders::BOTTOM) + .border_style(Style::new().fg(GHOST_WHITE)); + f.render_widget(dash, layer_two[2]); + + let buttons_layer = + Layout::horizontal(vec![Constraint::Percentage(50), Constraint::Percentage(50)]) + .split(layer_two[3]); + let button_ok = Line::from(vec![ + Span::styled("OK ", Style::default().fg(EUCALYPTUS)), + Span::styled("[Enter] ", Style::default().fg(GHOST_WHITE)), + ]) + .alignment(Alignment::Right); + + f.render_widget(button_ok, buttons_layer[1]); + + // We render now so the borders are on top of the other widgets + f.render_widget(pop_up_border, layer_zero); + } + + pub fn handle_input(&mut self, key: KeyEvent) -> bool { + if self.visible && (key.code == KeyCode::Esc || key.code == KeyCode::Enter) { + self.hide(); + true + } else { + false + } + } + + pub fn show(&mut self) { + debug!("Showing error popup"); + self.visible = true; + } + + pub fn hide(&mut self) { + debug!("Hiding error popup"); + self.visible = false; + } + + pub fn is_visible(&self) -> bool { + self.visible + } +} diff --git a/node-launchpad/src/lib.rs b/node-launchpad/src/lib.rs index aa18661f27..28e8535f42 100644 --- a/node-launchpad/src/lib.rs +++ b/node-launchpad/src/lib.rs @@ -11,6 +11,7 @@ pub mod app; pub mod components; pub mod config; pub mod connection_mode; +pub mod error; pub mod mode; pub mod node_mgmt; pub mod node_stats; diff --git a/node-launchpad/src/style.rs b/node-launchpad/src/style.rs index e4ae3c0c07..10e0cda89d 100644 --- a/node-launchpad/src/style.rs +++ b/node-launchpad/src/style.rs @@ -23,6 +23,7 @@ pub const SPACE_CADET: Color = Color::Indexed(17); pub const DARK_GUNMETAL: Color = Color::Indexed(235); // 266 is incorrect pub const INDIGO: Color = Color::Indexed(60); pub const VIVID_SKY_BLUE: Color = Color::Indexed(45); +pub const RED: Color = Color::Indexed(196); // Clears the area and sets the background color pub fn clear_area(f: &mut Frame<'_>, area: Rect) { From 6d47b23ec25ace5c82572eae6e0e359168a35a74 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 28 Aug 2024 15:07:13 +0200 Subject: [PATCH 20/35] fix(launchpad): flickering input field --- node-launchpad/src/components/popup/reset_nodes.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/node-launchpad/src/components/popup/reset_nodes.rs b/node-launchpad/src/components/popup/reset_nodes.rs index c021598278..7389b8e472 100644 --- a/node-launchpad/src/components/popup/reset_nodes.rs +++ b/node-launchpad/src/components/popup/reset_nodes.rs @@ -155,11 +155,7 @@ impl Component for ResetNodesPopup { let input = Paragraph::new(Span::styled( format!("{}{} ", spaces, self.confirmation_input_field.value()), - Style::default() - .fg(VIVID_SKY_BLUE) - .bg(INDIGO) - .underlined() - .underline_color(VIVID_SKY_BLUE), + Style::default().fg(VIVID_SKY_BLUE).bg(INDIGO).underlined(), )) .alignment(Alignment::Center); From b6e55e928a7c1f40e9d2f08a0ca037b32cf634e2 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 28 Aug 2024 15:09:07 +0200 Subject: [PATCH 21/35] feat(launchpad): nodes scaling up and down with custom ports --- .../src/components/popup/port_range.rs | 443 +++++++++++------- node-launchpad/src/components/status.rs | 76 +-- node-launchpad/src/node_mgmt.rs | 351 ++++++++++---- sn_node_manager/src/cmd/node.rs | 177 ++++--- 4 files changed, 673 insertions(+), 374 deletions(-) diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index 9b44116a08..d167724d0e 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -6,6 +6,9 @@ // KIND, either express or implied. Please review the Licences for the specific language governing // permissions and limitations relating to use of the SAFE Network Software. +use std::rc::Rc; + +use super::super::super::node_mgmt::{PORT_MAX, PORT_MIN}; use super::super::utils::centered_rect_fixed; use super::super::Component; use crate::{ @@ -19,14 +22,20 @@ use crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::{prelude::*, widgets::*}; use tui_input::{backend::crossterm::EventHandler, Input}; -pub const PORT_MAX: u32 = 65535; -pub const PORT_MIN: u32 = 1024; pub const PORT_ALLOCATION: u32 = 49; // We count the port_from as well const INPUT_SIZE: u32 = 5; const INPUT_AREA: u32 = INPUT_SIZE + 2; // +2 for the left and right padding +#[derive(Default)] +enum PortRangeState { + #[default] + Selection, + ConfirmChange, +} + pub struct PortRangePopUp { active: bool, + state: PortRangeState, connection_mode: ConnectionMode, port_from: Input, port_to: Input, @@ -39,6 +48,7 @@ impl PortRangePopUp { pub fn new(connection_mode: ConnectionMode, port_from: u32, port_to: u32) -> Self { Self { active: false, + state: PortRangeState::Selection, connection_mode, port_from: Input::default().with_value(port_from.to_string()), port_to: Input::default().with_value(port_to.to_string()), @@ -59,162 +69,16 @@ impl PortRangePopUp { && port_from <= port_to; } } -} - -impl Component for PortRangePopUp { - fn handle_key_events(&mut self, key: KeyEvent) -> Result> { - if !self.active { - return Ok(vec![]); - } - // while in entry mode, keybinds are not captured, so gotta exit entry mode from here - let send_back = match key.code { - KeyCode::Enter => { - let port_from = self.port_from.value(); - let port_to = self.port_to.value(); - - if port_from.is_empty() || port_to.is_empty() || !self.can_save { - debug!("Got Enter, but port_from or port_to is empty, ignoring."); - return Ok(vec![]); - } - debug!("Got Enter, saving the ports and switching to Options Screen",); - vec![ - Action::StorePortRange( - self.port_from.value().parse().unwrap_or_default(), - self.port_to.value().parse().unwrap_or_default(), - ), - Action::OptionsActions(OptionsActions::UpdatePortRange( - self.port_from.value().parse().unwrap_or_default(), - self.port_to.value().parse().unwrap_or_default(), - )), - Action::SwitchScene(Scene::Options), - ] - } - KeyCode::Esc => { - debug!("Got Esc, restoring the old values and switching to actual screen"); - // reset to old value - self.port_from = self - .port_from - .clone() - .with_value(self.port_from_old_value.to_string()); - self.port_to = self - .port_to - .clone() - .with_value(self.port_to_old_value.to_string()); - vec![Action::SwitchScene(Scene::Options)] - } - KeyCode::Char(c) if !c.is_numeric() => vec![], - KeyCode::Up => { - if self.port_from.value().parse::().unwrap_or_default() < PORT_MAX { - self.port_from = self.port_from.clone().with_value( - (self.port_from.value().parse::().unwrap_or_default() + 1).to_string(), - ); - let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); - if port_from_value + PORT_ALLOCATION <= PORT_MAX { - self.port_to = Input::default() - .with_value((port_from_value + PORT_ALLOCATION).to_string()); - } else { - self.port_to = Input::default().with_value("-".to_string()); - } - }; - self.validate(); - vec![] - } - KeyCode::Down => { - if self.port_from.value().parse::().unwrap_or_default() > 0 { - self.port_from = self.port_from.clone().with_value( - (self.port_from.value().parse::().unwrap_or_default() - 1).to_string(), - ); - let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); - if port_from_value + PORT_ALLOCATION <= PORT_MAX { - self.port_to = Input::default() - .with_value((port_from_value + PORT_ALLOCATION).to_string()); - } else { - self.port_to = Input::default().with_value("-".to_string()); - } - }; - self.validate(); - vec![] - } - KeyCode::Backspace => { - self.port_from.handle_event(&Event::Key(key)); - let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); - self.port_to = - Input::default().with_value((port_from_value + PORT_ALLOCATION).to_string()); - self.validate(); - vec![] - } - _ => { - // if max limit reached, we should not allow any more inputs. - if self.port_from.value().len() < INPUT_SIZE as usize { - self.port_from.handle_event(&Event::Key(key)); - let port_from_value: u32 = self.port_from.value().parse().unwrap_or_default(); - if port_from_value + PORT_ALLOCATION <= PORT_MAX { - self.port_to = Input::default() - .with_value((port_from_value + PORT_ALLOCATION).to_string()); - } else { - self.port_to = Input::default().with_value("-".to_string()); - } - }; - self.validate(); - vec![] - } - }; - Ok(send_back) - } - - fn update(&mut self, action: Action) -> Result> { - let send_back = match action { - Action::SwitchScene(scene) => match scene { - Scene::ChangePortsPopUp => { - if self.connection_mode == ConnectionMode::CustomPorts { - self.active = true; - self.validate(); - self.port_from_old_value = - self.port_from.value().parse().unwrap_or_default(); - self.port_to_old_value = self.port_to.value().parse().unwrap_or_default(); - // Set to InputMode::Entry as we want to handle everything within our handle_key_events - // so by default if this scene is active, we capture inputs. - Some(Action::SwitchInputMode(InputMode::Entry)) - } else { - self.active = false; - Some(Action::SwitchScene(Scene::Options)) - } - } - _ => { - self.active = false; - None - } - }, - // Useful when the user has selected a connection mode but didn't confirm it - Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { - self.connection_mode = connection_mode; - None - } - _ => None, - }; - Ok(send_back) - } - fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { - if !self.active { - return Ok(()); - } - - let layer_zero = centered_rect_fixed(52, 15, area); - - let layer_one = Layout::new( - Direction::Vertical, - [ - // for the pop_up_border - Constraint::Length(2), - // for the input field - Constraint::Min(1), - // for the pop_up_border - Constraint::Length(1), - ], - ) - .split(layer_zero); + // -- Draw functions -- + // Draws the Port Selection screen + fn draw_selection_state( + &mut self, + f: &mut crate::tui::Frame<'_>, + layer_zero: Rect, + layer_one: Rc<[Rect]>, + ) -> Paragraph { // layer zero let pop_up_border = Paragraph::new("").block( Block::default() @@ -256,11 +120,7 @@ impl Component for PortRangePopUp { let input_line = Line::from(vec![ Span::styled( format!("{}{} ", spaces_from, self.port_from.value()), - Style::default() - .fg(VIVID_SKY_BLUE) - .bg(INDIGO) - .underlined() - .underline_color(VIVID_SKY_BLUE), + Style::default().fg(VIVID_SKY_BLUE).bg(INDIGO).underlined(), ), Span::styled(" to ", Style::default().fg(GHOST_WHITE)), Span::styled( @@ -297,12 +157,265 @@ impl Component for PortRangePopUp { Style::default().fg(LIGHT_PERIWINKLE) }; f.render_widget(button_no, buttons_layer[0]); - let button_yes = Line::from(vec![Span::styled( - "Save Port Range [Enter]", - button_yes_style, - )]); + + let button_yes = Line::from(vec![ + Span::styled("Save Port Range ", button_yes_style), + Span::styled("[Enter]", Style::default().fg(GHOST_WHITE)), + ]); f.render_widget(button_yes, buttons_layer[1]); + pop_up_border + } + + // Draws the Confirmation screen + fn draw_confirm_change_state( + &mut self, + f: &mut crate::tui::Frame<'_>, + layer_zero: Rect, + layer_one: Rc<[Rect]>, + ) -> Paragraph { + // layer zero + let pop_up_border = Paragraph::new("").block( + Block::default() + .borders(Borders::ALL) + .title(" Port Forwarding For Private IPs ") + .title_style(Style::new().fg(VIVID_SKY_BLUE)) + .padding(Padding::uniform(2)) + .border_style(Style::new().fg(VIVID_SKY_BLUE)), + ); + clear_area(f, layer_zero); + + // split into 4 parts, for the prompt, input, text, dash , and buttons + let layer_two = Layout::new( + Direction::Vertical, + [ + // for the text + Constraint::Length(8), + // gap + Constraint::Length(3), + // for the buttons + Constraint::Length(1), + ], + ) + .split(layer_one[1]); + + let paragraph_text = Paragraph::new(vec![ + Line::from(Span::styled("\n\n",Style::default())), + Line::from(Span::styled("If you have a Private IP (which you probably do) you’ll now need to set your router to…\n\n", Style::default().fg(LIGHT_PERIWINKLE))), + Line::from(Span::styled("\n\n",Style::default())), + Line::from(Span::styled( + format!("Port Forward ports {}-{} ", self.port_from.value(), self.port_to.value()), + Style::default().fg(GHOST_WHITE), + )), + Line::from(Span::styled("\n\n",Style::default())), + Line::from(Span::styled("You can do this in your router’s admin panel.\n\n", Style::default().fg(LIGHT_PERIWINKLE))), + ]) + .alignment(Alignment::Left) + .wrap(Wrap { trim: true }) + .block(block::Block::default().padding(Padding::horizontal(2))); + + f.render_widget(paragraph_text, layer_two[0]); + + let dash = Block::new() + .borders(Borders::BOTTOM) + .border_style(Style::new().fg(GHOST_WHITE)); + f.render_widget(dash, layer_two[1]); + + let buttons_layer = + Layout::horizontal(vec![Constraint::Percentage(50), Constraint::Percentage(50)]) + .split(layer_two[2]); + + let button_ok = Line::from(vec![ + Span::styled("OK ", Style::default().fg(EUCALYPTUS)), + Span::styled("[Enter] ", Style::default().fg(GHOST_WHITE)), + ]) + .alignment(Alignment::Right); + + f.render_widget(button_ok, buttons_layer[1]); + + pop_up_border + } +} + +impl Component for PortRangePopUp { + fn handle_key_events(&mut self, key: KeyEvent) -> Result> { + if !self.active { + return Ok(vec![]); + } + // while in entry mode, keybinds are not captured, so gotta exit entry mode from here + let send_back: Vec = match &self.state { + PortRangeState::Selection => { + match key.code { + KeyCode::Enter => { + let port_from = self.port_from.value(); + let port_to = self.port_to.value(); + + if port_from.is_empty() || port_to.is_empty() || !self.can_save { + debug!("Got Enter, but port_from or port_to is empty, ignoring."); + return Ok(vec![]); + } + debug!("Got Enter, saving the ports and switching to Options Screen",); + self.state = PortRangeState::ConfirmChange; + vec![ + Action::StorePortRange( + self.port_from.value().parse().unwrap_or_default(), + self.port_to.value().parse().unwrap_or_default(), + ), + Action::OptionsActions(OptionsActions::UpdatePortRange( + self.port_from.value().parse().unwrap_or_default(), + self.port_to.value().parse().unwrap_or_default(), + )), + ] + } + KeyCode::Esc => { + debug!("Got Esc, restoring the old values and switching to actual screen"); + // reset to old value + self.port_from = self + .port_from + .clone() + .with_value(self.port_from_old_value.to_string()); + self.port_to = self + .port_to + .clone() + .with_value(self.port_to_old_value.to_string()); + vec![Action::SwitchScene(Scene::Options)] + } + KeyCode::Char(c) if !c.is_numeric() => vec![], + KeyCode::Up => { + if self.port_from.value().parse::().unwrap_or_default() < PORT_MAX { + self.port_from = self.port_from.clone().with_value( + (self.port_from.value().parse::().unwrap_or_default() + 1) + .to_string(), + ); + let port_from_value: u32 = + self.port_from.value().parse().unwrap_or_default(); + if port_from_value + PORT_ALLOCATION <= PORT_MAX { + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + } else { + self.port_to = Input::default().with_value("-".to_string()); + } + }; + self.validate(); + vec![] + } + KeyCode::Down => { + if self.port_from.value().parse::().unwrap_or_default() > 0 { + self.port_from = self.port_from.clone().with_value( + (self.port_from.value().parse::().unwrap_or_default() - 1) + .to_string(), + ); + let port_from_value: u32 = + self.port_from.value().parse().unwrap_or_default(); + if port_from_value + PORT_ALLOCATION <= PORT_MAX { + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + } else { + self.port_to = Input::default().with_value("-".to_string()); + } + }; + self.validate(); + vec![] + } + KeyCode::Backspace => { + self.port_from.handle_event(&Event::Key(key)); + let port_from_value: u32 = + self.port_from.value().parse().unwrap_or_default(); + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + self.validate(); + vec![] + } + _ => { + // if max limit reached, we should not allow any more inputs. + if self.port_from.value().len() < INPUT_SIZE as usize { + self.port_from.handle_event(&Event::Key(key)); + let port_from_value: u32 = + self.port_from.value().parse().unwrap_or_default(); + if port_from_value + PORT_ALLOCATION <= PORT_MAX { + self.port_to = Input::default() + .with_value((port_from_value + PORT_ALLOCATION).to_string()); + } else { + self.port_to = Input::default().with_value("-".to_string()); + } + }; + self.validate(); + vec![] + } + } + } + PortRangeState::ConfirmChange => match key.code { + KeyCode::Enter => { + debug!("Got Enter, saving the ports and switching to Options Screen",); + self.state = PortRangeState::Selection; + vec![Action::SwitchScene(Scene::Options)] + } + _ => vec![], + }, + }; + Ok(send_back) + } + + fn update(&mut self, action: Action) -> Result> { + let send_back = match action { + Action::SwitchScene(scene) => match scene { + Scene::ChangePortsPopUp => { + if self.connection_mode == ConnectionMode::CustomPorts { + self.active = true; + self.validate(); + self.port_from_old_value = + self.port_from.value().parse().unwrap_or_default(); + self.port_to_old_value = self.port_to.value().parse().unwrap_or_default(); + // Set to InputMode::Entry as we want to handle everything within our handle_key_events + // so by default if this scene is active, we capture inputs. + Some(Action::SwitchInputMode(InputMode::Entry)) + } else { + self.active = false; + Some(Action::SwitchScene(Scene::Options)) + } + } + _ => { + self.active = false; + None + } + }, + // Useful when the user has selected a connection mode but didn't confirm it + Action::OptionsActions(OptionsActions::UpdateConnectionMode(connection_mode)) => { + self.connection_mode = connection_mode; + None + } + _ => None, + }; + Ok(send_back) + } + + fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { + if !self.active { + return Ok(()); + } + + let layer_zero = centered_rect_fixed(52, 15, area); + + let layer_one = Layout::new( + Direction::Vertical, + [ + // for the pop_up_border + Constraint::Length(2), + // for the input field + Constraint::Min(1), + // for the pop_up_border + Constraint::Length(1), + ], + ) + .split(layer_zero); + + let pop_up_border: Paragraph = match self.state { + PortRangeState::Selection => self.draw_selection_state(f, layer_zero, layer_one), + PortRangeState::ConfirmChange => { + self.draw_confirm_change_state(f, layer_zero, layer_one) + } + }; + // We render now so the borders are on top of the other widgets f.render_widget(pop_up_border, layer_zero); Ok(()) diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 56a1207c86..5ee79c6fff 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -13,10 +13,11 @@ use super::{ Component, Frame, }; use crate::action::OptionsActions; -use crate::components::popup::port_range::{PORT_ALLOCATION, PORT_MAX, PORT_MIN}; +use crate::components::popup::port_range::PORT_ALLOCATION; use crate::config::get_launchpad_nodes_data_dir_path; use crate::connection_mode::ConnectionMode; use crate::node_mgmt::MaintainNodesArgs; +use crate::node_mgmt::{PORT_MAX, PORT_MIN}; use crate::{ action::{Action, StatusActions}, config::Config, @@ -164,7 +165,7 @@ impl Status { .filter(|node| node.status != ServiceStatus::Removed) .collect(); info!( - "Loaded node registry. Running nodes: {:?}", + "Loaded node registry. Maintaining {:?} nodes.", self.node_services.len() ); @@ -237,6 +238,16 @@ impl Status { .get(service_idx) .map(|data| data.service_name.clone()) } + + fn show_starting_nodes_popup(&mut self) { + debug!("Showing starting nodes popup"); + self.lock_registry = Some(LockRegistryState::StartingNodes); + } + + fn hide_starting_nodes_popup(&mut self) { + debug!("Hiding starting nodes popup"); + self.lock_registry = None; + } } impl Component for Status { @@ -322,6 +333,7 @@ impl Component for Status { } StatusActions::StartNodesCompleted | StatusActions::StopNodesCompleted => { self.lock_registry = None; + self.hide_starting_nodes_popup(); self.load_node_registry_and_update_states()?; } StatusActions::ResetNodesCompleted { trigger_start_node } => { @@ -330,6 +342,7 @@ impl Component for Status { if trigger_start_node { debug!("Reset nodes completed. Triggering start nodes."); + self.lock_registry = Some(LockRegistryState::StartingNodes); return Ok(Some(Action::StatusActions(StatusActions::StartNodes))); } debug!("Reset nodes completed"); @@ -358,10 +371,6 @@ impl Component for Status { } StatusActions::StartNodes => { debug!("Got action to start nodes"); - if self.lock_registry.is_some() { - error!("Registry is locked. Cannot start node now."); - return Ok(None); - } if self.nodes_to_start == 0 { info!("Nodes to start not set. Ask for input."); @@ -370,37 +379,26 @@ impl Component for Status { ))); } - // Port calculation - // Check if the port range is valid and we shorten the range based on the nodes to start - if self.port_from.unwrap_or(PORT_MIN) - 1 + self.nodes_to_start as u32 - > PORT_MAX - { - error!("Port range exceeds maximum port number. Cannot start nodes."); - //TODO: Give feedback to the user - return Ok(None); - } - - let port_range_str = if self.nodes_to_start > 1 { - format!( - "{}-{}", - self.port_from.unwrap_or(PORT_MIN), - self.port_from.unwrap_or(PORT_MIN) - 1 + self.nodes_to_start as u32 - ) - } else { - format!("{}", self.port_from.unwrap_or(PORT_MIN)) - }; - - let port_range = match PortRange::parse(&port_range_str) { - Ok(port_range) => port_range, - Err(err) => { - error!("When starting nodes, we got an error while parsing port range: {err:?}"); + if self.lock_registry.is_some() { + error!("Registry is locked. Attempting to unlock..."); + // Attempt to unlock the registry + self.lock_registry = None; + // Reload the node registry to ensure consistency + if let Err(e) = self.load_node_registry_and_update_states() { + //TODO: Show error & Popup + error!("Failed to reload node registry after unlocking: {:?}", e); return Ok(None); } - }; + } + self.show_starting_nodes_popup(); + + let port_range = PortRange::Range( + self.port_from.unwrap_or(PORT_MIN) as u16, + self.port_to.unwrap_or(PORT_MAX) as u16, + ); self.lock_registry = Some(LockRegistryState::StartingNodes); let action_sender = self.get_actions_sender()?; - info!("Running maintain node count: {:?}", self.nodes_to_start); let maintain_nodes_args = MaintainNodesArgs { count: self.nodes_to_start as u16, @@ -415,9 +413,12 @@ impl Component for Status { port_range: Some(port_range), }; - //TODO: Handle errors and give feedback to the user - stop_nodes(self.get_running_nodes(), action_sender.clone()); + debug!("Calling maintain_n_running_nodes"); + maintain_n_running_nodes(maintain_nodes_args); + + self.lock_registry = None; + self.load_node_registry_and_update_states()?; } StatusActions::StopNodes => { debug!("Got action to stop nodes"); @@ -541,8 +542,9 @@ impl Component for Status { ]); // Combine "Nanos Earned" and "Discord Username" into a single row + let discord_username_placeholder = "Discord Username: "; // Used to calculate the width of the username column let discord_username_title = Span::styled( - "Discord Username: ".to_string(), + discord_username_placeholder, Style::default().fg(VIVID_SKY_BLUE), ); @@ -579,8 +581,10 @@ impl Component for Status { let stats_width = [Constraint::Length(5)]; let column_constraints = [ Constraint::Length(23), - Constraint::Percentage(25), Constraint::Fill(1), + Constraint::Length( + (discord_username_placeholder.len() + self.discord_username.len()) as u16, + ), ]; let stats_table = Table::new(stats_rows, stats_width) .block( diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index f3c81b4de4..ff804b81fe 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -1,14 +1,20 @@ use std::path::PathBuf; -use sn_node_manager::{add_services::config::PortRange, VerbosityLevel}; +use sn_node_manager::{ + add_services::config::PortRange, config::get_node_registry_path, VerbosityLevel, +}; use sn_peers_acquisition::PeersArgs; +use sn_service_management::NodeRegistry; use tokio::sync::mpsc::UnboundedSender; use crate::action::{Action, StatusActions}; -use color_eyre::eyre::Result; use crate::connection_mode::ConnectionMode; +pub const PORT_MAX: u32 = 65535; +pub const PORT_MIN: u32 = 1024; + +/// Stop the specified services pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) { tokio::task::spawn_local(async move { if let Err(err) = @@ -38,108 +44,42 @@ pub struct MaintainNodesArgs { pub port_range: Option, } +/// Maintain the specified number of nodes pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { + debug!("Maintaining {} nodes", args.count); tokio::task::spawn_local(async move { if args.run_nat_detection { - info!("Running nat detection...."); - if let Err(err) = run_nat_detection_process().await { - error!("Error while running nat detection {err:?}. Registering the error."); - if let Err(err) = args.action_sender.send(Action::StatusActions( - StatusActions::ErrorWhileRunningNatDetection, - )) { - error!("Error while sending action: {err:?}"); - } - } else { - info!("Successfully ran nat detection."); - } + run_nat_detection(&args.action_sender).await; } - let auto_set_nat_flags: bool = args.connection_mode == ConnectionMode::Automatic; - let upnp: bool = args.connection_mode == ConnectionMode::UPnP; - let home_network: bool = args.connection_mode == ConnectionMode::HomeNetwork; - let custom_ports: Option = if args.connection_mode == ConnectionMode::CustomPorts - { - match args.port_range { - Some(port_range) => { - debug!("Port range to run nodes: {port_range:?}"); - Some(port_range) - } - None => { - debug!("Port range not provided. Using default port range."); - None - } - } - } else { - None - }; - let owner = if args.owner.is_empty() { - None - } else { - Some(args.owner) - }; - - debug!("************"); - debug!( - "Maintaining {} running nodes with the following args:", - args.count - ); - debug!( - " owner: {:?}, peers_args: {:?}, safenode_path: {:?}", - owner, args.peers_args, args.safenode_path - ); - debug!( - " data_dir_path: {:?}, connection_mode: {:?}", - args.data_dir_path, args.connection_mode - ); - debug!( - " auto_set_nat_flags: {:?}, custom_ports: {:?}, upnp: {}, home_network: {}", - auto_set_nat_flags, custom_ports, upnp, home_network - ); - - if let Err(err) = sn_node_manager::cmd::node::maintain_n_running_nodes( - false, - auto_set_nat_flags, - 120, - args.count, - args.data_dir_path, - true, - None, - home_network, - false, - None, - None, - None, - custom_ports, - owner, - args.peers_args, - None, - None, - args.safenode_path, - None, - upnp, - None, - None, - VerbosityLevel::Minimal, - None, - ) - .await - { - error!( - "Error while maintaining {:?} running nodes {err:?}", - args.count - ); + let config = prepare_node_config(&args); + debug_log_config(&config, &args); + + let node_registry = NodeRegistry::load(&get_node_registry_path().unwrap()).unwrap(); //FIXME: unwrap + let mut used_ports = get_used_ports(&node_registry); + let (mut current_port, max_port) = get_port_range(&config.custom_ports); + + let nodes_to_add = args.count as i32 - node_registry.nodes.len() as i32; + + if nodes_to_add <= 0 { + scale_down_nodes(&config, args.count).await; } else { - info!("Maintained {} running nodes successfully.", args.count); - } - if let Err(err) = args - .action_sender - .send(Action::StatusActions(StatusActions::StartNodesCompleted)) - { - error!("Error while sending action: {err:?}"); + add_nodes( + &config, + nodes_to_add, + &mut used_ports, + &mut current_port, + max_port, + ) + .await; } + + debug!("Finished maintaining {} nodes", args.count); + send_completion_action(&args.action_sender); }); } +/// Reset all the nodes pub fn reset_nodes(action_sender: UnboundedSender, start_nodes_after_reset: bool) { tokio::task::spawn_local(async move { if let Err(err) = sn_node_manager::cmd::node::reset(true, VerbosityLevel::Minimal).await { @@ -157,15 +97,228 @@ pub fn reset_nodes(action_sender: UnboundedSender, start_nodes_after_res }); } -async fn run_nat_detection_process() -> Result<()> { - sn_node_manager::cmd::nat_detection::run_nat_detection( +// --- Helper functions --- + +struct NodeConfig { + auto_set_nat_flags: bool, + upnp: bool, + home_network: bool, + custom_ports: Option, + owner: Option, + count: u16, + data_dir_path: Option, + peers_args: PeersArgs, + safenode_path: Option, +} + +/// Run the NAT detection process +async fn run_nat_detection(action_sender: &UnboundedSender) { + info!("Running nat detection...."); + if let Err(err) = sn_node_manager::cmd::nat_detection::run_nat_detection( None, true, None, None, - Some("0.1.0".to_string()), + Some("0.1.0".to_string()), //FIXME: hardcoded version!! VerbosityLevel::Minimal, ) - .await?; - Ok(()) + .await + { + error!("Error while running nat detection {err:?}. Registering the error."); + if let Err(err) = action_sender.send(Action::StatusActions( + StatusActions::ErrorWhileRunningNatDetection, + )) { + error!("Error while sending action: {err:?}"); + } + } else { + info!("Successfully ran nat detection."); + } +} + +fn prepare_node_config(args: &MaintainNodesArgs) -> NodeConfig { + NodeConfig { + auto_set_nat_flags: args.connection_mode == ConnectionMode::Automatic, + upnp: args.connection_mode == ConnectionMode::UPnP, + home_network: args.connection_mode == ConnectionMode::HomeNetwork, + custom_ports: if args.connection_mode == ConnectionMode::CustomPorts { + args.port_range.clone() + } else { + None + }, + owner: if args.owner.is_empty() { + None + } else { + Some(args.owner.clone()) + }, + count: args.count, + data_dir_path: args.data_dir_path.clone(), + peers_args: args.peers_args.clone(), + safenode_path: args.safenode_path.clone(), + } +} + +/// Debug log the node config +fn debug_log_config(config: &NodeConfig, args: &MaintainNodesArgs) { + debug!("************ STARTING NODE MAINTENANCE ************"); + debug!( + "Maintaining {} running nodes with the following args:", + config.count + ); + debug!( + " owner: {:?}, peers_args: {:?}, safenode_path: {:?}", + config.owner, config.peers_args, config.safenode_path + ); + debug!( + " data_dir_path: {:?}, connection_mode: {:?}", + config.data_dir_path, args.connection_mode + ); + debug!( + " auto_set_nat_flags: {:?}, custom_ports: {:?}, upnp: {}, home_network: {}", + config.auto_set_nat_flags, config.custom_ports, config.upnp, config.home_network + ); +} + +/// Get the currently used ports from the node registry +fn get_used_ports(node_registry: &NodeRegistry) -> Vec { + let used_ports: Vec = node_registry + .nodes + .iter() + .filter_map(|node| node.node_port) + .collect(); + debug!("Currently used ports: {:?}", used_ports); + used_ports +} + +/// Get the port range (u16, u16) from the custom ports PortRange +fn get_port_range(custom_ports: &Option) -> (u16, u16) { + match custom_ports { + Some(PortRange::Single(port)) => (*port, *port), + Some(PortRange::Range(start, end)) => (*start, *end), + None => (PORT_MIN as u16, PORT_MAX as u16), + } +} + +/// Scale down the nodes +async fn scale_down_nodes(config: &NodeConfig, count: u16) { + info!("No nodes to add"); + match sn_node_manager::cmd::node::maintain_n_running_nodes( + false, + config.auto_set_nat_flags, + 120, + count, + config.data_dir_path.clone(), + true, + None, + config.home_network, + false, + None, + None, + None, + None, // We don't care about the port, as we are scaling down + config.owner.clone(), + config.peers_args.clone(), + None, + None, + config.safenode_path.clone(), + None, + config.upnp, + None, + None, + VerbosityLevel::Minimal, + None, + ) + .await + { + Ok(_) => { + info!("Scaling down to {} nodes", count); + } + Err(err) => { + error!("Error while scaling down to {} nodes: {err:?}", count); + } + } +} + +/// Add the specified number of nodes +async fn add_nodes( + config: &NodeConfig, + mut nodes_to_add: i32, + used_ports: &mut Vec, + current_port: &mut u16, + max_port: u16, +) { + let mut retry_count = 0; + let max_retries = 5; + + while nodes_to_add > 0 && retry_count < max_retries { + // Find the next available port + while used_ports.contains(current_port) && *current_port <= max_port { + *current_port += 1; + } + + if *current_port > max_port { + error!("Reached maximum port number. Unable to find an available port."); + break; + } + + let port_range = Some(PortRange::Single(*current_port)); + match sn_node_manager::cmd::node::maintain_n_running_nodes( + false, + config.auto_set_nat_flags, + 120, + config.count, + config.data_dir_path.clone(), + true, + None, + config.home_network, + false, + None, + None, + None, + port_range, + config.owner.clone(), + config.peers_args.clone(), + None, + None, + config.safenode_path.clone(), + None, + config.upnp, + None, + None, + VerbosityLevel::Minimal, + None, + ) + .await + { + Ok(_) => { + info!("Successfully added a node on port {}", current_port); + used_ports.push(*current_port); + nodes_to_add -= 1; + *current_port += 1; + retry_count = 0; // Reset retry count on success + } + Err(err) => { + if err.to_string().contains("is being used by another service") { + warn!( + "Port {} is being used, retrying with a different port. Attempt {}/{}", + current_port, + retry_count + 1, + max_retries + ); + *current_port += 1; + retry_count += 1; + } else { + error!("Error while adding node on port {}: {err:?}", current_port); + retry_count += 1; + } + } + } + } +} + +/// Send the completion action +fn send_completion_action(action_sender: &UnboundedSender) { + if let Err(err) = action_sender.send(Action::StatusActions(StatusActions::StartNodesCompleted)) + { + error!("Error while sending action: {err:?}"); + } } diff --git a/sn_node_manager/src/cmd/node.rs b/sn_node_manager/src/cmd/node.rs index bca1e536ed..20f31ffea6 100644 --- a/sn_node_manager/src/cmd/node.rs +++ b/sn_node_manager/src/cmd/node.rs @@ -615,58 +615,51 @@ pub async fn maintain_n_running_nodes( let running_nodes = node_registry .nodes .iter() - .filter_map(|node| { - if node.status == ServiceStatus::Running { - Some(node.service_name.clone()) - } else { - None - } - }) + .filter(|node| node.status == ServiceStatus::Running) + .map(|node| node.service_name.clone()) .collect::>(); - match running_nodes.len().cmp(&(max_nodes_to_run as usize)) { + let running_count = running_nodes.len(); + let target_count = max_nodes_to_run as usize; + + info!( + "Current running nodes: {}, Target: {}", + running_count, target_count + ); + + match running_count.cmp(&target_count) { Ordering::Greater => { - // stop some nodes if we are running more nodes than needed. - let to_stop_count = running_nodes.len() - max_nodes_to_run as usize; + let to_stop_count = running_count - target_count; let services_to_stop = running_nodes .into_iter() + .rev() // Stop the oldest nodes first .take(to_stop_count) .collect::>(); info!( - ?max_nodes_to_run, - ?to_stop_count, - "We are stopping these services: {services_to_stop:?}" + "Stopping {} excess nodes: {:?}", + to_stop_count, services_to_stop ); - stop(vec![], services_to_stop, verbosity).await?; } Ordering::Less => { - // Run some nodes - let to_start_count = max_nodes_to_run as usize - running_nodes.len(); - - let mut inactive_nodes = node_registry + let to_start_count = target_count - running_count; + let inactive_nodes = node_registry .nodes .iter() - .filter_map(|node| { - if node.status == ServiceStatus::Stopped || node.status == ServiceStatus::Added - { - Some(node.service_name.clone()) - } else { - None - } + .filter(|node| { + node.status == ServiceStatus::Stopped || node.status == ServiceStatus::Added }) + .map(|node| node.service_name.clone()) .collect::>(); - // If we have enough inactive nodes, then we can just start them. Else we might have to add new ones and - // then start them. + info!("Inactive nodes available: {}", inactive_nodes.len()); + if to_start_count <= inactive_nodes.len() { - // start these nodes let nodes_to_start = inactive_nodes.into_iter().take(to_start_count).collect(); info!( - ?max_nodes_to_run, - ?to_start_count, - "We are starting these pre-existing services: {nodes_to_start:?}" + "Starting {} existing inactive nodes: {:?}", + to_start_count, nodes_to_start ); start( connection_timeout_s, @@ -677,60 +670,96 @@ pub async fn maintain_n_running_nodes( ) .await?; } else { - // add + start nodes let to_add_count = to_start_count - inactive_nodes.len(); - info!( - ?max_nodes_to_run, - ?to_add_count, - "We are adding+starting {to_add_count:?} nodes + starting these services: {inactive_nodes:?}" - ); - - let added_service_list = add( - auto_restart, - auto_set_nat_flags, - Some(to_add_count as u16), - data_dir_path, - enable_metrics_server, - env_variables, - home_network, - local, - log_dir_path, - log_format, - metrics_port, - node_port, - owner, - peers, - rpc_address, - rpc_port, - src_path, - upnp, - url, - user, - version, - verbosity, - ) - .await?; - inactive_nodes.extend(added_service_list); + "Adding {} new nodes and starting all {} inactive nodes", + to_add_count, + inactive_nodes.len() + ); - start( - connection_timeout_s, - start_node_interval, - vec![], - inactive_nodes, - verbosity, - ) - .await?; + let ports_to_use = match node_port { + Some(PortRange::Single(port)) => vec![port], + Some(PortRange::Range(start, end)) => { + (start..=end).take(to_add_count).collect() + } + None => vec![], + }; + + for (i, port) in ports_to_use.into_iter().enumerate() { + let added_service = add( + auto_restart, + auto_set_nat_flags, + Some(1), + data_dir_path.clone(), + enable_metrics_server, + env_variables.clone(), + home_network, + local, + log_dir_path.clone(), + log_format, + metrics_port.clone(), + Some(PortRange::Single(port)), + owner.clone(), + peers.clone(), + rpc_address, + rpc_port.clone(), + src_path.clone(), + upnp, + url.clone(), + user.clone(), + version.clone(), + verbosity, + ) + .await?; + + if i == 0 { + start( + connection_timeout_s, + start_node_interval, + vec![], + added_service, + verbosity, + ) + .await?; + } + } + + if !inactive_nodes.is_empty() { + start( + connection_timeout_s, + start_node_interval, + vec![], + inactive_nodes, + verbosity, + ) + .await?; + } } } Ordering::Equal => { info!( - ?max_nodes_to_run, - "We already have the correct number of nodes. Do nothing." + "Current node count ({}) matches target ({}). No action needed.", + running_count, target_count ); } } + // Verify final state + let final_node_registry = NodeRegistry::load(&config::get_node_registry_path()?)?; + let final_running_count = final_node_registry + .nodes + .iter() + .filter(|node| node.status == ServiceStatus::Running) + .count(); + + info!("Final running node count: {}", final_running_count); + if final_running_count != target_count { + warn!( + "Failed to reach target node count. Expected {}, but got {}", + target_count, final_running_count + ); + } + Ok(()) } From 54f437e4f9f751e2b4f081301e381e0e25bb01c5 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 28 Aug 2024 15:09:43 +0200 Subject: [PATCH 22/35] fix(launchpad): app not runing without app_data --- node-launchpad/src/app.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index 668f308308..7b44daa9d0 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -24,6 +24,7 @@ use crate::{ config::{get_launchpad_nodes_data_dir_path, AppData, Config}, connection_mode::ConnectionMode, mode::{InputMode, Scene}, + node_mgmt::{PORT_MAX, PORT_MIN}, style::SPACE_CADET, system::{get_default_mount_point, get_primary_mount_point, get_primary_mount_point_name}, tui, @@ -94,7 +95,7 @@ impl App { peers_args, safenode_path, data_dir_path, - connection_mode, + connection_mode: connection_mode.clone(), port_from: Some(port_from), port_to: Some(port_to), }; @@ -259,10 +260,10 @@ impl App { self.app_data.connection_mode = Some(mode.clone()); self.app_data.save(None)?; } - Action::StorePortRange(from, to) => { + Action::StorePortRange(ref from, ref to) => { debug!("Storing port range: {from:?}, {to:?}"); - self.app_data.port_from = Some(from); - self.app_data.port_to = Some(to); + self.app_data.port_from = Some(*from); + self.app_data.port_to = Some(*to); self.app_data.save(None)?; } Action::StoreDiscordUserName(ref username) => { @@ -270,15 +271,9 @@ impl App { self.app_data.discord_username.clone_from(username); self.app_data.save(None)?; } - Action::StoreNodesToStart(count) => { + Action::StoreNodesToStart(ref count) => { debug!("Storing nodes to start: {count:?}"); - self.app_data.nodes_to_start = count; - self.app_data.save(None)?; - } - Action::StoreStorageDrive(ref drive_mountpoint, ref drive_name) => { - debug!("Storing storage drive: {drive_mountpoint:?}, {drive_name:?}"); - self.app_data.storage_mountpoint = Some(drive_mountpoint.clone()); - self.app_data.storage_drive = Some(drive_name.as_str().to_string()); + self.app_data.nodes_to_start = *count; self.app_data.save(None)?; } _ => {} From ae6f76badbd94f537e19dee9a4e31896cdeb379e Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Wed, 28 Aug 2024 19:27:44 +0200 Subject: [PATCH 23/35] feat(launchpad): status feedback and latest nat crate feedback --- node-launchpad/src/components/status.rs | 52 ++++++++++++------------- node-launchpad/src/node_mgmt.rs | 23 ++++++++++- 2 files changed, 47 insertions(+), 28 deletions(-) diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 5ee79c6fff..aaad4dab6b 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -238,16 +238,6 @@ impl Status { .get(service_idx) .map(|data| data.service_name.clone()) } - - fn show_starting_nodes_popup(&mut self) { - debug!("Showing starting nodes popup"); - self.lock_registry = Some(LockRegistryState::StartingNodes); - } - - fn hide_starting_nodes_popup(&mut self) { - debug!("Hiding starting nodes popup"); - self.lock_registry = None; - } } impl Component for Status { @@ -298,6 +288,7 @@ impl Component for Status { self.discord_username = username; if we_have_nodes && has_changed { + debug!("Setting lock_registry to ResettingNodes"); self.lock_registry = Some(LockRegistryState::ResettingNodes); info!("Resetting safenode services because the Discord Username was reset."); let action_sender = self.get_actions_sender()?; @@ -305,6 +296,7 @@ impl Component for Status { } } Action::StoreStorageDrive(ref drive_mountpoint, ref _drive_name) => { + debug!("Setting lock_registry to ResettingNodes"); self.lock_registry = Some(LockRegistryState::ResettingNodes); info!("Resetting safenode services because the Storage Drive was changed."); let action_sender = self.get_actions_sender()?; @@ -313,16 +305,18 @@ impl Component for Status { get_launchpad_nodes_data_dir_path(&drive_mountpoint.to_path_buf(), false)?; } Action::StoreConnectionMode(connection_mode) => { - self.connection_mode = connection_mode; + debug!("Setting lock_registry to ResettingNodes"); self.lock_registry = Some(LockRegistryState::ResettingNodes); + self.connection_mode = connection_mode; info!("Resetting safenode services because the Connection Mode range was changed."); let action_sender = self.get_actions_sender()?; reset_nodes(action_sender, false); } Action::StorePortRange(port_from, port_range) => { + debug!("Setting lock_registry to ResettingNodes"); + self.lock_registry = Some(LockRegistryState::ResettingNodes); self.port_from = Some(port_from); self.port_to = Some(port_range); - self.lock_registry = Some(LockRegistryState::ResettingNodes); info!("Resetting safenode services because the Port Range was changed."); let action_sender = self.get_actions_sender()?; reset_nodes(action_sender, false); @@ -332,16 +326,18 @@ impl Component for Status { self.node_stats = stats; } StatusActions::StartNodesCompleted | StatusActions::StopNodesCompleted => { + debug!("Setting lock_registry to None"); self.lock_registry = None; - self.hide_starting_nodes_popup(); self.load_node_registry_and_update_states()?; } StatusActions::ResetNodesCompleted { trigger_start_node } => { + debug!("Setting lock_registry to None"); self.lock_registry = None; self.load_node_registry_and_update_states()?; if trigger_start_node { debug!("Reset nodes completed. Triggering start nodes."); + debug!("Setting lock_registry to StartingNodes"); self.lock_registry = Some(LockRegistryState::StartingNodes); return Ok(Some(Action::StatusActions(StatusActions::StartNodes))); } @@ -382,6 +378,7 @@ impl Component for Status { if self.lock_registry.is_some() { error!("Registry is locked. Attempting to unlock..."); // Attempt to unlock the registry + debug!("Setting lock_registry to None"); self.lock_registry = None; // Reload the node registry to ensure consistency if let Err(e) = self.load_node_registry_and_update_states() { @@ -390,22 +387,21 @@ impl Component for Status { return Ok(None); } } - self.show_starting_nodes_popup(); + debug!("Setting lock_registry to StartingNodes"); + self.lock_registry = Some(LockRegistryState::StartingNodes); let port_range = PortRange::Range( self.port_from.unwrap_or(PORT_MIN) as u16, self.port_to.unwrap_or(PORT_MAX) as u16, ); - self.lock_registry = Some(LockRegistryState::StartingNodes); let action_sender = self.get_actions_sender()?; let maintain_nodes_args = MaintainNodesArgs { count: self.nodes_to_start as u16, owner: self.discord_username.clone(), peers_args: self.peers_args.clone(), - run_nat_detection: self.should_we_run_nat_detection() - && self.connection_mode == ConnectionMode::Automatic, + run_nat_detection: self.should_we_run_nat_detection(), safenode_path: self.safenode_path.clone(), data_dir_path: Some(self.data_dir_path.clone()), action_sender: action_sender.clone(), @@ -416,9 +412,6 @@ impl Component for Status { debug!("Calling maintain_n_running_nodes"); maintain_n_running_nodes(maintain_nodes_args); - - self.lock_registry = None; - self.load_node_registry_and_update_states()?; } StatusActions::StopNodes => { debug!("Got action to stop nodes"); @@ -428,6 +421,7 @@ impl Component for Status { } let running_nodes = self.get_running_nodes(); + debug!("Setting lock_registry to StoppingNodes"); self.lock_registry = Some(LockRegistryState::StoppingNodes); let action_sender = self.get_actions_sender()?; info!("Stopping node service: {running_nodes:?}"); @@ -442,6 +436,7 @@ impl Component for Status { return Ok(None); } + debug!("Setting lock_registry to ResettingNodes"); self.lock_registry = Some(LockRegistryState::ResettingNodes); let action_sender = self.get_actions_sender()?; info!("Got action to reset nodes"); @@ -711,7 +706,12 @@ impl Component for Status { Line::raw("This may take a couple minutes."), ] } else { - vec![Line::raw("Starting nodes...")] + vec![ + Line::raw(""), + Line::raw(""), + Line::raw(""), + Line::raw("Starting nodes..."), + ] } } LockRegistryState::StoppingNodes => vec![Line::raw("Stopping nodes...")], @@ -721,22 +721,20 @@ impl Component for Status { Direction::Vertical, vec![ // border - Constraint::Length(1), - Constraint::Min(1), + Constraint::Length(2), // our text goes here - Constraint::Length(3), - Constraint::Min(1), + Constraint::Min(5), // border Constraint::Length(1), ], ) - .split(popup_area)[2]; + .split(popup_area); let text = Paragraph::new(popup_text) .block(Block::default().padding(Padding::horizontal(2))) .wrap(Wrap { trim: false }) .alignment(Alignment::Center) .fg(EUCALYPTUS); - f.render_widget(text, centred_area); + f.render_widget(text, centred_area[1]); f.render_widget(popup_border, popup_area); } diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index ff804b81fe..e914847fd5 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -11,6 +11,8 @@ use crate::action::{Action, StatusActions}; use crate::connection_mode::ConnectionMode; +use sn_releases::{self, ReleaseType, SafeReleaseRepoActions}; + pub const PORT_MAX: u32 = 65535; pub const PORT_MIN: u32 = 1024; @@ -62,8 +64,10 @@ pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { let nodes_to_add = args.count as i32 - node_registry.nodes.len() as i32; if nodes_to_add <= 0 { + debug!("Scaling down nodes to {}", nodes_to_add); scale_down_nodes(&config, args.count).await; } else { + debug!("Scaling up nodes to {}", nodes_to_add); add_nodes( &config, nodes_to_add, @@ -114,12 +118,29 @@ struct NodeConfig { /// Run the NAT detection process async fn run_nat_detection(action_sender: &UnboundedSender) { info!("Running nat detection...."); + + let release_repo = ::default_config(); + let version = match release_repo + .get_latest_version(&ReleaseType::NatDetection) + .await + { + Ok(v) => { + info!("Using NAT detection version {}", v.to_string()); + v.to_string() + } + Err(err) => { + info!("No NAT detection release found, using fallback version 0.1.0"); + info!("Error: {err}"); + "0.1.0".to_string() + } + }; + if let Err(err) = sn_node_manager::cmd::nat_detection::run_nat_detection( None, true, None, None, - Some("0.1.0".to_string()), //FIXME: hardcoded version!! + Some(version), VerbosityLevel::Minimal, ) .await From f15adcc6d5a8d0d222955fb751f1ffb055738b4d Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 29 Aug 2024 09:32:24 +0200 Subject: [PATCH 24/35] chore(launchpad): update sn releases dependency --- Cargo.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index abdbd3cd97..1aa0e7b690 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3426,7 +3426,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core 0.51.1", ] [[package]] From 03b8db042750d149e3e63afc731304b4da3cc9dc Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 29 Aug 2024 10:21:15 +0200 Subject: [PATCH 25/35] fix(launchpad): we cannot set to none the registry --- node-launchpad/src/components/status.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index aaad4dab6b..6add4d3ebd 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -376,17 +376,10 @@ impl Component for Status { } if self.lock_registry.is_some() { - error!("Registry is locked. Attempting to unlock..."); - // Attempt to unlock the registry - debug!("Setting lock_registry to None"); - self.lock_registry = None; - // Reload the node registry to ensure consistency - if let Err(e) = self.load_node_registry_and_update_states() { - //TODO: Show error & Popup - error!("Failed to reload node registry after unlocking: {:?}", e); - return Ok(None); - } + error!("Registry is locked. Cannot start node now."); + return Ok(None); } + debug!("Setting lock_registry to StartingNodes"); self.lock_registry = Some(LockRegistryState::StartingNodes); From ce6c15fc469b240b0c3e67aeb59571d949fc8265 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 29 Aug 2024 10:21:58 +0200 Subject: [PATCH 26/35] chore(launchpad): todo message --- node-launchpad/src/node_mgmt.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index e914847fd5..333c33de00 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -318,6 +318,7 @@ async fn add_nodes( retry_count = 0; // Reset retry count on success } Err(err) => { + //TODO: We should use concrete error types here instead of string matching (sn_node_manager) if err.to_string().contains("is being used by another service") { warn!( "Port {} is being used, retrying with a different port. Attempt {}/{}", From c58b4f3800c6b6f01bfe521ee4b63c35910dced4 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 29 Aug 2024 15:41:30 +0200 Subject: [PATCH 27/35] feat(launchpad): error messages on status screen --- node-launchpad/src/action.rs | 6 +- .../src/components/popup/port_range.rs | 3 +- node-launchpad/src/components/status.rs | 99 +++++++++++++++++-- node-launchpad/src/error.rs | 16 ++- node-launchpad/src/node_mgmt.rs | 92 ++++++++++++++--- 5 files changed, 190 insertions(+), 26 deletions(-) diff --git a/node-launchpad/src/action.rs b/node-launchpad/src/action.rs index 8ab87cf0eb..19b8bc7125 100644 --- a/node-launchpad/src/action.rs +++ b/node-launchpad/src/action.rs @@ -50,7 +50,11 @@ pub enum StatusActions { ResetNodesCompleted { trigger_start_node: bool }, SuccessfullyDetectedNatStatus, ErrorWhileRunningNatDetection, - + ErrorLoadingNodeRegistry { raw_error: String }, + ErrorGettingNodeRegistryPath { raw_error: String }, + ErrorScalingUpNodes { raw_error: String }, + ErrorStoppingNodes { raw_error: String }, + ErrorResettingNodes { raw_error: String }, NodesStatsObtained(NodeStats), TriggerManageNodes, diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index d167724d0e..c3a41c0fe5 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -11,6 +11,7 @@ use std::rc::Rc; use super::super::super::node_mgmt::{PORT_MAX, PORT_MIN}; use super::super::utils::centered_rect_fixed; use super::super::Component; +use super::manage_nodes::MAX_NODE_COUNT; use crate::{ action::{Action, OptionsActions}, connection_mode::ConnectionMode, @@ -22,7 +23,7 @@ use crossterm::event::{Event, KeyCode, KeyEvent}; use ratatui::{prelude::*, widgets::*}; use tui_input::{backend::crossterm::EventHandler, Input}; -pub const PORT_ALLOCATION: u32 = 49; // We count the port_from as well +pub const PORT_ALLOCATION: u32 = MAX_NODE_COUNT as u32 - 1; // We count the port_from as well const INPUT_SIZE: u32 = 5; const INPUT_AREA: u32 = INPUT_SIZE + 2; // +2 for the left and right padding diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 6add4d3ebd..9d349278ce 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -16,8 +16,10 @@ use crate::action::OptionsActions; use crate::components::popup::port_range::PORT_ALLOCATION; use crate::config::get_launchpad_nodes_data_dir_path; use crate::connection_mode::ConnectionMode; +use crate::error::ErrorPopup; use crate::node_mgmt::MaintainNodesArgs; use crate::node_mgmt::{PORT_MAX, PORT_MIN}; +use crate::tui::Event; use crate::{ action::{Action, StatusActions}, config::Config, @@ -80,6 +82,7 @@ pub struct Status { port_from: Option, // Port to port_to: Option, + error_popup: Option, } #[derive(Clone)] @@ -121,6 +124,7 @@ impl Status { connection_mode: config.connection_mode, port_from: config.port_from, port_to: config.port_to, + error_popup: None, }; let now = Instant::now(); @@ -255,6 +259,14 @@ impl Component for Status { Ok(()) } + fn handle_events(&mut self, event: Option) -> Result> { + let r = match event { + Some(Event::Key(key_event)) => self.handle_key_events(key_event)?, + _ => vec![], + }; + Ok(r) + } + #[allow(clippy::comparison_chain)] fn update(&mut self, action: Action) -> Result> { match action { @@ -326,19 +338,15 @@ impl Component for Status { self.node_stats = stats; } StatusActions::StartNodesCompleted | StatusActions::StopNodesCompleted => { - debug!("Setting lock_registry to None"); self.lock_registry = None; self.load_node_registry_and_update_states()?; } StatusActions::ResetNodesCompleted { trigger_start_node } => { - debug!("Setting lock_registry to None"); self.lock_registry = None; self.load_node_registry_and_update_states()?; if trigger_start_node { debug!("Reset nodes completed. Triggering start nodes."); - debug!("Setting lock_registry to StartingNodes"); - self.lock_registry = Some(LockRegistryState::StartingNodes); return Ok(Some(Action::StatusActions(StatusActions::StartNodes))); } debug!("Reset nodes completed"); @@ -356,6 +364,55 @@ impl Component for Status { self.error_while_running_nat_detection ); } + StatusActions::ErrorLoadingNodeRegistry { raw_error } + | StatusActions::ErrorGettingNodeRegistryPath { raw_error } => { + self.error_popup = Some(ErrorPopup::new( + " Error ".to_string(), + "Error getting node registry path".to_string(), + raw_error, + )); + if let Some(error_popup) = &mut self.error_popup { + error_popup.show(); + } + // Switch back to entry mode so we can handle key events + return Ok(Some(Action::SwitchInputMode(InputMode::Entry))); + } + StatusActions::ErrorScalingUpNodes { raw_error } => { + self.error_popup = Some(ErrorPopup::new( + " Error ".to_string(), + "Error adding new nodes".to_string(), + raw_error, + )); + if let Some(error_popup) = &mut self.error_popup { + error_popup.show(); + } + // Switch back to entry mode so we can handle key events + return Ok(Some(Action::SwitchInputMode(InputMode::Entry))); + } + StatusActions::ErrorStoppingNodes { raw_error } => { + self.error_popup = Some(ErrorPopup::new( + " Error ".to_string(), + "Error stopping nodes".to_string(), + raw_error, + )); + if let Some(error_popup) = &mut self.error_popup { + error_popup.show(); + } + // Switch back to entry mode so we can handle key events + return Ok(Some(Action::SwitchInputMode(InputMode::Entry))); + } + StatusActions::ErrorResettingNodes { raw_error } => { + self.error_popup = Some(ErrorPopup::new( + " Error ".to_string(), + "Error resetting nodes".to_string(), + raw_error, + )); + if let Some(error_popup) = &mut self.error_popup { + error_popup.show(); + } + // Switch back to entry mode so we can handle key events + return Ok(Some(Action::SwitchInputMode(InputMode::Entry))); + } StatusActions::TriggerManageNodes => { return Ok(Some(Action::SwitchScene(Scene::ManageNodesPopUp))); } @@ -675,6 +732,16 @@ impl Component for Status { // ===== Popup ===== + // Error Popup + if let Some(error_popup) = &self.error_popup { + if error_popup.is_visible() { + error_popup.draw_error(f, area); + + return Ok(()); + } + } + + // Status Popup if let Some(registry_state) = &self.lock_registry { let popup_area = centered_rect_fixed(50, 12, area); clear_area(f, popup_area); @@ -707,8 +774,22 @@ impl Component for Status { ] } } - LockRegistryState::StoppingNodes => vec![Line::raw("Stopping nodes...")], - LockRegistryState::ResettingNodes => vec![Line::raw("Resetting nodes...")], + LockRegistryState::StoppingNodes => { + vec![ + Line::raw(""), + Line::raw(""), + Line::raw(""), + Line::raw("Stopping nodes..."), + ] + } + LockRegistryState::ResettingNodes => { + vec![ + Line::raw(""), + Line::raw(""), + Line::raw(""), + Line::raw("Resetting nodes..."), + ] + } }; let centred_area = Layout::new( Direction::Vertical, @@ -737,6 +818,12 @@ impl Component for Status { fn handle_key_events(&mut self, key: KeyEvent) -> Result> { debug!("Key received in Status: {:?}", key); + if let Some(error_popup) = &mut self.error_popup { + if error_popup.is_visible() { + error_popup.handle_input(key); + return Ok(vec![Action::SwitchInputMode(InputMode::Navigation)]); + } + } Ok(vec![]) } } diff --git a/node-launchpad/src/error.rs b/node-launchpad/src/error.rs index 352bbfa8fd..9f05fe292c 100644 --- a/node-launchpad/src/error.rs +++ b/node-launchpad/src/error.rs @@ -45,18 +45,21 @@ use ratatui::{ /// if let Some(error_popup) = &mut self.error_popup { /// if error_popup.is_visible() { /// error_popup.handle_input(key); -/// return Ok(vec![]); +/// return Ok(vec![Action::SwitchInputMode(InputMode::Navigation)]); /// } /// } /// // ... Your keys being handled here ... /// } /// fn draw(&mut self, f: &mut crate::tui::Frame<'_>, area: Rect) -> Result<()> { +/// // ... Your drawing code here ... +/// // Be sure to include the background elements here /// if let Some(error_popup) = &self.error_popup { /// if error_popup.is_visible() { /// error_popup.draw_error(f, area); /// return Ok(()); /// } /// } +/// // Be sure to include your popups here /// // ... Your drawing code here ... /// } /// } @@ -75,6 +78,7 @@ use ratatui::{ /// } /// ``` +#[derive(Clone)] pub struct ErrorPopup { visible: bool, title: String, @@ -126,9 +130,9 @@ impl ErrorPopup { Direction::Vertical, [ // for the message - Constraint::Length(5), + Constraint::Length(4), // for the error_message - Constraint::Length(5), + Constraint::Length(7), // gap Constraint::Length(1), // for the buttons @@ -138,7 +142,11 @@ impl ErrorPopup { .split(layer_one[1]); let prompt = Paragraph::new(self.message.clone()) - .block(Block::default().padding(Padding::horizontal(2))) + .block( + Block::default() + .padding(Padding::horizontal(2)) + .padding(Padding::vertical(1)), + ) .alignment(Alignment::Center) .wrap(Wrap { trim: true }); diff --git a/node-launchpad/src/node_mgmt.rs b/node-launchpad/src/node_mgmt.rs index 333c33de00..88c48dd566 100644 --- a/node-launchpad/src/node_mgmt.rs +++ b/node-launchpad/src/node_mgmt.rs @@ -1,5 +1,6 @@ use std::path::PathBuf; +use color_eyre::eyre::{eyre, Error}; use sn_node_manager::{ add_services::config::PortRange, config::get_node_registry_path, VerbosityLevel, }; @@ -16,6 +17,8 @@ use sn_releases::{self, ReleaseType, SafeReleaseRepoActions}; pub const PORT_MAX: u32 = 65535; pub const PORT_MIN: u32 = 1024; +const PORT_ASSIGNMENT_MAX_RETRIES: u32 = 5; + /// Stop the specified services pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) { tokio::task::spawn_local(async move { @@ -23,6 +26,13 @@ pub fn stop_nodes(services: Vec, action_sender: UnboundedSender) sn_node_manager::cmd::node::stop(vec![], services, VerbosityLevel::Minimal).await { error!("Error while stopping services {err:?}"); + if let Err(err) = + action_sender.send(Action::StatusActions(StatusActions::ErrorStoppingNodes { + raw_error: err.to_string(), + })) + { + error!("Error while sending action: {err:?}"); + } } else { info!("Successfully stopped services"); } @@ -57,7 +67,13 @@ pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { let config = prepare_node_config(&args); debug_log_config(&config, &args); - let node_registry = NodeRegistry::load(&get_node_registry_path().unwrap()).unwrap(); //FIXME: unwrap + let node_registry = match load_node_registry(&args.action_sender).await { + Ok(registry) => registry, + Err(err) => { + error!("Failed to load node registry: {:?}", err); + return; + } + }; let mut used_ports = get_used_ports(&node_registry); let (mut current_port, max_port) = get_port_range(&config.custom_ports); @@ -69,6 +85,7 @@ pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { } else { debug!("Scaling up nodes to {}", nodes_to_add); add_nodes( + &args.action_sender, &config, nodes_to_add, &mut used_ports, @@ -79,7 +96,12 @@ pub fn maintain_n_running_nodes(args: MaintainNodesArgs) { } debug!("Finished maintaining {} nodes", args.count); - send_completion_action(&args.action_sender); + if let Err(err) = args + .action_sender + .send(Action::StatusActions(StatusActions::StartNodesCompleted)) + { + error!("Error while sending action: {err:?}"); + } }); } @@ -88,6 +110,13 @@ pub fn reset_nodes(action_sender: UnboundedSender, start_nodes_after_res tokio::task::spawn_local(async move { if let Err(err) = sn_node_manager::cmd::node::reset(true, VerbosityLevel::Minimal).await { error!("Error while resetting services {err:?}"); + if let Err(err) = + action_sender.send(Action::StatusActions(StatusActions::ErrorResettingNodes { + raw_error: err.to_string(), + })) + { + error!("Error while sending action: {err:?}"); + } } else { info!("Successfully reset services"); } @@ -103,6 +132,39 @@ pub fn reset_nodes(action_sender: UnboundedSender, start_nodes_after_res // --- Helper functions --- +/// Load the node registry and handle errors +async fn load_node_registry( + action_sender: &UnboundedSender, +) -> Result { + match get_node_registry_path() { + Ok(path) => match NodeRegistry::load(&path) { + Ok(registry) => Ok(registry), + Err(err) => { + error!("Failed to load NodeRegistry: {}", err); + if let Err(send_err) = action_sender.send(Action::StatusActions( + StatusActions::ErrorLoadingNodeRegistry { + raw_error: err.to_string(), + }, + )) { + error!("Error while sending action: {}", send_err); + } + Err(eyre!("Failed to load NodeRegistry")) + } + }, + Err(err) => { + error!("Failed to get node registry path: {}", err); + if let Err(send_err) = action_sender.send(Action::StatusActions( + StatusActions::ErrorGettingNodeRegistryPath { + raw_error: err.to_string(), + }, + )) { + error!("Error while sending action: {}", send_err); + } + Err(eyre!("Failed to get node registry path")) + } + } +} + struct NodeConfig { auto_set_nat_flags: bool, upnp: bool, @@ -221,7 +283,6 @@ fn get_port_range(custom_ports: &Option) -> (u16, u16) { /// Scale down the nodes async fn scale_down_nodes(config: &NodeConfig, count: u16) { - info!("No nodes to add"); match sn_node_manager::cmd::node::maintain_n_running_nodes( false, config.auto_set_nat_flags, @@ -261,6 +322,7 @@ async fn scale_down_nodes(config: &NodeConfig, count: u16) { /// Add the specified number of nodes async fn add_nodes( + action_sender: &UnboundedSender, config: &NodeConfig, mut nodes_to_add: i32, used_ports: &mut Vec, @@ -268,9 +330,8 @@ async fn add_nodes( max_port: u16, ) { let mut retry_count = 0; - let max_retries = 5; - while nodes_to_add > 0 && retry_count < max_retries { + while nodes_to_add > 0 && retry_count < PORT_ASSIGNMENT_MAX_RETRIES { // Find the next available port while used_ports.contains(current_port) && *current_port <= max_port { *current_port += 1; @@ -278,6 +339,16 @@ async fn add_nodes( if *current_port > max_port { error!("Reached maximum port number. Unable to find an available port."); + if let Err(err) = + action_sender.send(Action::StatusActions(StatusActions::ErrorScalingUpNodes { + raw_error: format!( + "Reached maximum port number ({}).\nUnable to find an available port.", + max_port + ), + })) + { + error!("Error while sending action: {err:?}"); + } break; } @@ -324,11 +395,12 @@ async fn add_nodes( "Port {} is being used, retrying with a different port. Attempt {}/{}", current_port, retry_count + 1, - max_retries + PORT_ASSIGNMENT_MAX_RETRIES ); *current_port += 1; retry_count += 1; } else { + error!("Range of ports to be used {:?}", *current_port..max_port); error!("Error while adding node on port {}: {err:?}", current_port); retry_count += 1; } @@ -336,11 +408,3 @@ async fn add_nodes( } } } - -/// Send the completion action -fn send_completion_action(action_sender: &UnboundedSender) { - if let Err(err) = action_sender.send(Action::StatusActions(StatusActions::StartNodesCompleted)) - { - error!("Error while sending action: {err:?}"); - } -} From 4212eb8c945f0872066e70f173cb572b383fbdef Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Thu, 29 Aug 2024 15:49:21 +0200 Subject: [PATCH 28/35] fix(launchpad): not resetting when ports do not change --- node-launchpad/src/components/popup/port_range.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index c3a41c0fe5..f97c18cd61 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -248,6 +248,14 @@ impl Component for PortRangePopUp { PortRangeState::Selection => { match key.code { KeyCode::Enter => { + if self.port_from_old_value + == self.port_from.value().parse::().unwrap_or_default() + && self.port_to_old_value + == self.port_to.value().parse::().unwrap_or_default() + { + debug!("Got Enter, but nothing changed, ignoring."); + return Ok(vec![Action::SwitchScene(Scene::Options)]); + } let port_from = self.port_from.value(); let port_to = self.port_to.value(); From 9d26c084915210fc1704d0e82318d92289e701a6 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 2 Sep 2024 13:28:15 +0200 Subject: [PATCH 29/35] fix(launchpad): default ports and cancel during setting the ports --- node-launchpad/src/app.rs | 11 +++++--- node-launchpad/src/components/options.rs | 6 +++-- .../src/components/popup/connection_mode.rs | 12 +++++---- .../src/components/popup/port_range.rs | 25 +++++++++++++++++-- node-launchpad/src/components/status.rs | 2 +- node-launchpad/src/connection_mode.rs | 2 +- node-launchpad/src/mode.rs | 6 ++++- 7 files changed, 48 insertions(+), 16 deletions(-) diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index 7b44daa9d0..d5e8083148 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -73,7 +73,7 @@ impl App { }; debug!("Data dir path for nodes: {data_dir_path:?}"); - // App data validations + // App data default values let connection_mode = app_data .connection_mode .unwrap_or(ConnectionMode::Automatic); @@ -95,7 +95,7 @@ impl App { peers_args, safenode_path, data_dir_path, - connection_mode: connection_mode.clone(), + connection_mode, port_from: Some(port_from), port_to: Some(port_to), }; @@ -114,7 +114,10 @@ impl App { // Popups let reset_nodes = ResetNodesPopup::default(); - let discord_username_input = BetaProgramme::new(app_data.discord_username.clone()); + let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; + let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; + let port_range = PortRangePopUp::new(connection_mode, port_from, port_to); + let beta_programme = BetaProgramme::new(app_data.discord_username.clone()); let manage_nodes = ManageNodes::new(app_data.nodes_to_start, storage_mountpoint.clone())?; let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; @@ -257,7 +260,7 @@ impl App { } Action::StoreConnectionMode(ref mode) => { debug!("Storing connection mode: {mode:?}"); - self.app_data.connection_mode = Some(mode.clone()); + self.app_data.connection_mode = Some(*mode); self.app_data.save(None)?; } Action::StorePortRange(ref from, ref to) => { diff --git a/node-launchpad/src/components/options.rs b/node-launchpad/src/components/options.rs index d2605f1759..3a2c8658fc 100644 --- a/node-launchpad/src/components/options.rs +++ b/node-launchpad/src/components/options.rs @@ -348,7 +348,7 @@ impl Component for Options { Scene::Options | Scene::ChangeDrivePopUp | Scene::ChangeConnectionModePopUp - | Scene::ChangePortsPopUp + | Scene::ChangePortsPopUp { .. } | Scene::BetaProgrammePopUp | Scene::ResetNodesPopUp => { self.active = true; @@ -372,7 +372,9 @@ impl Component for Options { self.connection_mode = mode; } OptionsActions::TriggerChangePortRange => { - return Ok(Some(Action::SwitchScene(Scene::ChangePortsPopUp))); + return Ok(Some(Action::SwitchScene(Scene::ChangePortsPopUp { + connection_mode_old_value: None, + }))); } OptionsActions::UpdatePortRange(from, to) => { self.port_from = Some(from); diff --git a/node-launchpad/src/components/popup/connection_mode.rs b/node-launchpad/src/components/popup/connection_mode.rs index 3e0b4b8b8f..134a068e3b 100644 --- a/node-launchpad/src/components/popup/connection_mode.rs +++ b/node-launchpad/src/components/popup/connection_mode.rs @@ -45,7 +45,7 @@ impl ChangeConnectionModePopUp { let mut selected_connection_mode: ConnectionModeItem = ConnectionModeItem::default(); let connection_modes_items: Vec = ConnectionMode::iter() .map(|connection_mode_item| ConnectionModeItem { - connection_mode: connection_mode_item.clone(), + connection_mode: connection_mode_item, status: if connection_mode == connection_mode_item { selected_connection_mode = ConnectionModeItem { connection_mode: connection_mode_item, @@ -128,14 +128,16 @@ impl Component for ChangeConnectionModePopUp { self.connection_mode_initial_state = self.connection_mode_selection.clone(); self.assign_connection_mode_selection(); vec![ - Action::StoreConnectionMode( - self.connection_mode_selection.connection_mode.clone(), - ), + Action::StoreConnectionMode(self.connection_mode_selection.connection_mode), Action::OptionsActions(OptionsActions::UpdateConnectionMode( connection_mode.clone().connection_mode, )), if connection_mode.connection_mode == ConnectionMode::CustomPorts { - Action::SwitchScene(Scene::ChangePortsPopUp) + Action::SwitchScene(Scene::ChangePortsPopUp { + connection_mode_old_value: Some( + self.connection_mode_initial_state.connection_mode, + ), + }) } else { Action::SwitchScene(Scene::Options) }, diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index f97c18cd61..6565c1097b 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -38,6 +38,7 @@ pub struct PortRangePopUp { active: bool, state: PortRangeState, connection_mode: ConnectionMode, + connection_mode_old_value: Option, port_from: Input, port_to: Input, port_from_old_value: u32, @@ -51,6 +52,7 @@ impl PortRangePopUp { active: false, state: PortRangeState::Selection, connection_mode, + connection_mode_old_value: None, port_from: Input::default().with_value(port_from.to_string()), port_to: Input::default().with_value(port_to.to_string()), port_from_old_value: Default::default(), @@ -252,6 +254,7 @@ impl Component for PortRangePopUp { == self.port_from.value().parse::().unwrap_or_default() && self.port_to_old_value == self.port_to.value().parse::().unwrap_or_default() + && self.can_save { debug!("Got Enter, but nothing changed, ignoring."); return Ok(vec![Action::SwitchScene(Scene::Options)]); @@ -278,7 +281,22 @@ impl Component for PortRangePopUp { } KeyCode::Esc => { debug!("Got Esc, restoring the old values and switching to actual screen"); - // reset to old value + // if the old values are 0 means that is the first time the user opens the app, + // so we should set the connection mode to automatic. + if self.port_from_old_value.to_string() == "0" + && self.port_to_old_value.to_string() == "0" + { + self.connection_mode = self + .connection_mode_old_value + .unwrap_or(ConnectionMode::Automatic); + return Ok(vec![ + Action::StoreConnectionMode(self.connection_mode), + Action::OptionsActions(OptionsActions::UpdateConnectionMode( + self.connection_mode, + )), + Action::SwitchScene(Scene::Options), + ]); + } self.port_from = self .port_from .clone() @@ -368,9 +386,12 @@ impl Component for PortRangePopUp { fn update(&mut self, action: Action) -> Result> { let send_back = match action { Action::SwitchScene(scene) => match scene { - Scene::ChangePortsPopUp => { + Scene::ChangePortsPopUp { + connection_mode_old_value, + } => { if self.connection_mode == ConnectionMode::CustomPorts { self.active = true; + self.connection_mode_old_value = connection_mode_old_value; self.validate(); self.port_from_old_value = self.port_from.value().parse().unwrap_or_default(); diff --git a/node-launchpad/src/components/status.rs b/node-launchpad/src/components/status.rs index 9d349278ce..c3088e4cd1 100644 --- a/node-launchpad/src/components/status.rs +++ b/node-launchpad/src/components/status.rs @@ -455,7 +455,7 @@ impl Component for Status { safenode_path: self.safenode_path.clone(), data_dir_path: Some(self.data_dir_path.clone()), action_sender: action_sender.clone(), - connection_mode: self.connection_mode.clone(), + connection_mode: self.connection_mode, port_range: Some(port_range), }; diff --git a/node-launchpad/src/connection_mode.rs b/node-launchpad/src/connection_mode.rs index 51286d7b0a..c3f5290327 100644 --- a/node-launchpad/src/connection_mode.rs +++ b/node-launchpad/src/connection_mode.rs @@ -3,7 +3,7 @@ use std::fmt::{Display, Formatter, Result}; use serde::{Deserialize, Serialize}; use strum::EnumIter; -#[derive(Clone, Debug, Default, EnumIter, Eq, PartialEq)] +#[derive(Clone, Copy, Debug, Default, EnumIter, Eq, Hash, PartialEq)] pub enum ConnectionMode { #[default] Automatic, diff --git a/node-launchpad/src/mode.rs b/node-launchpad/src/mode.rs index 9a515383e5..2f0d356599 100644 --- a/node-launchpad/src/mode.rs +++ b/node-launchpad/src/mode.rs @@ -8,6 +8,8 @@ use serde::{Deserialize, Serialize}; +use crate::connection_mode::ConnectionMode; + #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Scene { #[default] @@ -16,7 +18,9 @@ pub enum Scene { Help, ChangeDrivePopUp, ChangeConnectionModePopUp, - ChangePortsPopUp, + ChangePortsPopUp { + connection_mode_old_value: Option, + }, BetaProgrammePopUp, ManageNodesPopUp, ResetNodesPopUp, From 389d02d3948b5ad2eb05ef22fc732a55d7279c88 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 2 Sep 2024 13:40:52 +0200 Subject: [PATCH 30/35] feat(launchpad): port range validation user feedback --- .../src/components/popup/port_range.rs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/node-launchpad/src/components/popup/port_range.rs b/node-launchpad/src/components/popup/port_range.rs index 6565c1097b..491294a96a 100644 --- a/node-launchpad/src/components/popup/port_range.rs +++ b/node-launchpad/src/components/popup/port_range.rs @@ -12,6 +12,7 @@ use super::super::super::node_mgmt::{PORT_MAX, PORT_MIN}; use super::super::utils::centered_rect_fixed; use super::super::Component; use super::manage_nodes::MAX_NODE_COUNT; +use crate::style::RED; use crate::{ action::{Action, OptionsActions}, connection_mode::ConnectionMode, @@ -123,7 +124,10 @@ impl PortRangePopUp { let input_line = Line::from(vec![ Span::styled( format!("{}{} ", spaces_from, self.port_from.value()), - Style::default().fg(VIVID_SKY_BLUE).bg(INDIGO).underlined(), + Style::default() + .fg(if self.can_save { VIVID_SKY_BLUE } else { RED }) + .bg(INDIGO) + .underlined(), ), Span::styled(" to ", Style::default().fg(GHOST_WHITE)), Span::styled( @@ -135,10 +139,22 @@ impl PortRangePopUp { f.render_widget(input_line, layer_two[1]); - let text = Paragraph::new("Choose the start of the port range. The range will then match the number of nodes on this device.") - .block(block::Block::default().padding(Padding::horizontal(2))) - .alignment(Alignment::Center) - .wrap(Wrap { trim: true }); + let text = Paragraph::new(vec![ + Line::from(Span::styled( + format!( + "Choose the start of the range of {} ports.", + PORT_ALLOCATION + 1 + ), + Style::default().fg(GHOST_WHITE), + )), + Line::from(Span::styled( + format!("This must be between {} and {}.", PORT_MIN, PORT_MAX), + Style::default().fg(if self.can_save { GHOST_WHITE } else { RED }), + )), + ]) + .block(block::Block::default().padding(Padding::horizontal(2))) + .alignment(Alignment::Center) + .wrap(Wrap { trim: true }); f.render_widget(text.fg(GHOST_WHITE), layer_two[2]); let dash = Block::new() From 34f9c0bf79d857dc404f7beb194f9ede0855ebb0 Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 2 Sep 2024 18:22:13 +0200 Subject: [PATCH 31/35] test(launchpad): avoid executing code in comments --- node-launchpad/src/error.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node-launchpad/src/error.rs b/node-launchpad/src/error.rs index 9f05fe292c..1f487ee558 100644 --- a/node-launchpad/src/error.rs +++ b/node-launchpad/src/error.rs @@ -25,7 +25,7 @@ use ratatui::{ /// 6. Handle the input for the error popup by calling the `handle_input` method. /// /// Example: -/// ```rust +/// ```ignore /// use crate::error::ErrorPopup; /// /// pub struct MyComponent { @@ -67,7 +67,7 @@ use ratatui::{ /// /// How to trigger the error /// -/// ```rust +/// ```ignore /// self.error_popup = Some(ErrorPopup::new( /// "Error".to_string(), /// "This is a test error message".to_string(), From a91fde0c803f287bd8b7c9f3b41415524bf89e0f Mon Sep 17 00:00:00 2001 From: Lautaro Mazzitelli Date: Mon, 2 Sep 2024 18:22:40 +0200 Subject: [PATCH 32/35] chore(launchpad): fixing merge conflicts --- node-launchpad/src/app.rs | 117 +++++++++++++++++++++++++++++------ node-launchpad/src/config.rs | 61 ++++++------------ 2 files changed, 116 insertions(+), 62 deletions(-) diff --git a/node-launchpad/src/app.rs b/node-launchpad/src/app.rs index d5e8083148..f5163a5837 100644 --- a/node-launchpad/src/app.rs +++ b/node-launchpad/src/app.rs @@ -114,10 +114,6 @@ impl App { // Popups let reset_nodes = ResetNodesPopup::default(); - let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; - let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; - let port_range = PortRangePopUp::new(connection_mode, port_from, port_to); - let beta_programme = BetaProgramme::new(app_data.discord_username.clone()); let manage_nodes = ManageNodes::new(app_data.nodes_to_start, storage_mountpoint.clone())?; let change_drive = ChangeDrivePopup::new(storage_mountpoint.clone())?; let change_connection_mode = ChangeConnectionModePopUp::new(connection_mode)?; @@ -126,7 +122,15 @@ impl App { Ok(Self { config, - app_data, + app_data: AppData { + discord_username: app_data.discord_username.clone(), + nodes_to_start: app_data.nodes_to_start, + storage_mountpoint: Some(storage_mountpoint), + storage_drive: Some(storage_drive), + connection_mode: Some(connection_mode), + port_from: Some(port_from), + port_to: Some(port_to), + }, tick_rate, frame_rate, components: vec![ @@ -322,14 +326,17 @@ mod tests { let mountpoint = get_primary_mount_point(); - // Create a valid configuration file + // Create a valid configuration file with all fields let valid_config = format!( r#" {{ "discord_username": "happy_user", "nodes_to_start": 5, "storage_mountpoint": "{}", - "storage_drive": "C:" + "storage_drive": "C:", + "connection_mode": "Automatic", + "port_from": 12000, + "port_to": 13000 }} "#, mountpoint.display() @@ -348,13 +355,17 @@ mod tests { match app_result { Ok(app) => { - // Check if the discord_username and nodes_to_start were correctly loaded + // Check if all fields were correctly loaded assert_eq!(app.app_data.discord_username, "happy_user"); assert_eq!(app.app_data.nodes_to_start, 5); - // Check if the storage_mountpoint is set correctly assert_eq!(app.app_data.storage_mountpoint, Some(mountpoint)); - // Check if the storage_drive is set correctly assert_eq!(app.app_data.storage_drive, Some("C:".to_string())); + assert_eq!( + app.app_data.connection_mode, + Some(ConnectionMode::Automatic) + ); + assert_eq!(app.app_data.port_from, Some(12000)); + assert_eq!(app.app_data.port_to, Some(13000)); write!(output, "App created successfully with valid configuration")?; } @@ -382,11 +393,14 @@ mod tests { let temp_dir = tempdir()?; let test_app_data_path = temp_dir.path().join("test_app_data.json"); - // Create a custom configuration file with only the first two settings + // Create a custom configuration file with only some settings let custom_config = r#" { "discord_username": "test_user", - "nodes_to_start": 3 + "nodes_to_start": 3, + "connection_mode": "Custom Ports", + "port_from": 12000, + "port_to": 13000 } "#; std::fs::write(&test_app_data_path, custom_config)?; @@ -402,13 +416,20 @@ mod tests { match app_result { Ok(app) => { - // Check if the discord_username and nodes_to_start were correctly loaded + // Check if the fields were correctly loaded assert_eq!(app.app_data.discord_username, "test_user"); assert_eq!(app.app_data.nodes_to_start, 3); - // Check if the storage_mountpoint is None (not set) - assert_eq!(app.app_data.storage_mountpoint, None); - // Check if the storage_drive is None (not set) - assert_eq!(app.app_data.storage_drive, None); + // Check if the storage_mountpoint is Some (automatically set) + assert!(app.app_data.storage_mountpoint.is_some()); + // Check if the storage_drive is Some (automatically set) + assert!(app.app_data.storage_drive.is_some()); + // Check the new fields + assert_eq!( + app.app_data.connection_mode, + Some(ConnectionMode::CustomPorts) + ); + assert_eq!(app.app_data.port_from, Some(12000)); + assert_eq!(app.app_data.port_to, Some(13000)); write!( output, @@ -453,8 +474,14 @@ mod tests { Ok(app) => { assert_eq!(app.app_data.discord_username, ""); assert_eq!(app.app_data.nodes_to_start, 1); - assert_eq!(app.app_data.storage_mountpoint, None); - assert_eq!(app.app_data.storage_drive, None); + assert!(app.app_data.storage_mountpoint.is_some()); + assert!(app.app_data.storage_drive.is_some()); + assert_eq!( + app.app_data.connection_mode, + Some(ConnectionMode::Automatic) + ); + assert_eq!(app.app_data.port_from, Some(PORT_MIN)); + assert_eq!(app.app_data.port_to, Some(PORT_MAX)); write!( output, @@ -491,7 +518,10 @@ mod tests { "discord_username": "test_user", "nodes_to_start": 5, "storage_mountpoint": "/non/existent/path", - "storage_drive": "Z:" + "storage_drive": "Z:", + "connection_mode": "Custom Ports", + "port_from": 12000, + "port_to": 13000 } "#; std::fs::write(&config_path, invalid_config)?; @@ -521,4 +551,51 @@ mod tests { Ok(()) } + + #[tokio::test] + async fn test_app_default_connection_mode_and_ports() -> Result<()> { + // Create a temporary directory for our test + let temp_dir = tempdir()?; + let test_app_data_path = temp_dir.path().join("test_app_data.json"); + + // Create a custom configuration file without connection mode and ports + let custom_config = r#" + { + "discord_username": "test_user", + "nodes_to_start": 3 + } + "#; + std::fs::write(&test_app_data_path, custom_config)?; + + // Create default PeersArgs + let peers_args = PeersArgs::default(); + + // Create and run the App + let app_result = App::new(60.0, 60.0, peers_args, None, Some(test_app_data_path)).await; + + match app_result { + Ok(app) => { + // Check if the discord_username and nodes_to_start were correctly loaded + assert_eq!(app.app_data.discord_username, "test_user"); + assert_eq!(app.app_data.nodes_to_start, 3); + + // Check if the connection_mode is set to the default (Automatic) + assert_eq!( + app.app_data.connection_mode, + Some(ConnectionMode::Automatic) + ); + + // Check if the port range is set to the default values + assert_eq!(app.app_data.port_from, Some(PORT_MIN)); + assert_eq!(app.app_data.port_to, Some(PORT_MAX)); + + println!("App created successfully with default connection mode and ports"); + } + Err(e) => { + panic!("App creation failed: {}", e); + } + } + + Ok(()) + } } diff --git a/node-launchpad/src/config.rs b/node-launchpad/src/config.rs index 59dfe3a975..93b0bd60be 100644 --- a/node-launchpad/src/config.rs +++ b/node-launchpad/src/config.rs @@ -7,7 +7,6 @@ // permissions and limitations relating to use of the SAFE Network Software. use crate::connection_mode::ConnectionMode; -use crate::system; use crate::system::get_primary_mount_point; use crate::{action::Action, mode::Scene}; use color_eyre::eyre::{eyre, Result}; @@ -141,20 +140,9 @@ impl AppData { let data = std::fs::read_to_string(&config_path) .map_err(|_| color_eyre::eyre::eyre!("Failed to read app data file"))?; - let mut app_data: AppData = serde_json::from_str(&data) + let app_data: AppData = serde_json::from_str(&data) .map_err(|_| color_eyre::eyre::eyre!("Failed to parse app data"))?; - if app_data.storage_mountpoint.is_none() || app_data.storage_drive.is_none() { - // If the storage drive is not set, set it to the default mount point - let drive_info = system::get_default_mount_point()?; - app_data.storage_drive = Some(drive_info.0); - app_data.storage_mountpoint = Some(drive_info.1); - debug!("Setting storage drive to {:?}", app_data.storage_mountpoint); - } - - if app_data.connection_mode.is_none() { - app_data.connection_mode = Some(ConnectionMode::default()); - } Ok(app_data) } @@ -724,6 +712,9 @@ mod tests { assert_eq!(app_data.nodes_to_start, 1); assert_eq!(app_data.storage_mountpoint, None); assert_eq!(app_data.storage_drive, None); + assert_eq!(app_data.connection_mode, None); + assert_eq!(app_data.port_from, None); + assert_eq!(app_data.port_to, None); Ok(()) } @@ -748,6 +739,9 @@ mod tests { assert_eq!(app_data.nodes_to_start, 3); assert_eq!(app_data.storage_mountpoint, None); assert_eq!(app_data.storage_drive, None); + assert_eq!(app_data.connection_mode, None); + assert_eq!(app_data.port_from, None); + assert_eq!(app_data.port_to, None); Ok(()) } @@ -773,35 +767,9 @@ mod tests { assert_eq!(app_data.nodes_to_start, 3); assert_eq!(app_data.storage_mountpoint, None); assert_eq!(app_data.storage_drive, Some("C:".to_string())); - - Ok(()) - } - - #[test] - fn test_app_data_complete_info() -> Result<()> { - let temp_dir = tempdir()?; - let complete_data_path = temp_dir.path().join("complete_app_data.json"); - - let complete_data = r#" - { - "discord_username": "complete_user", - "nodes_to_start": 5, - "storage_mountpoint": "/mnt/data", - "storage_drive": "D:" - } - "#; - - std::fs::write(&complete_data_path, complete_data)?; - - let app_data = AppData::load(Some(complete_data_path))?; - - assert_eq!(app_data.discord_username, "complete_user"); - assert_eq!(app_data.nodes_to_start, 5); - assert_eq!( - app_data.storage_mountpoint, - Some(PathBuf::from("/mnt/data")) - ); - assert_eq!(app_data.storage_drive, Some("D:".to_string())); + assert_eq!(app_data.connection_mode, None); + assert_eq!(app_data.port_from, None); + assert_eq!(app_data.port_to, None); Ok(()) } @@ -817,6 +785,9 @@ mod tests { app_data.nodes_to_start = 4; app_data.storage_mountpoint = Some(PathBuf::from("/mnt/test")); app_data.storage_drive = Some("E:".to_string()); + app_data.connection_mode = Some(ConnectionMode::CustomPorts); + app_data.port_from = Some(12000); + app_data.port_to = Some(13000); // Save to custom path app_data.save(Some(test_path.clone()))?; @@ -831,6 +802,12 @@ mod tests { Some(PathBuf::from("/mnt/test")) ); assert_eq!(loaded_data.storage_drive, Some("E:".to_string())); + assert_eq!( + loaded_data.connection_mode, + Some(ConnectionMode::CustomPorts) + ); + assert_eq!(loaded_data.port_from, Some(12000)); + assert_eq!(loaded_data.port_to, Some(13000)); Ok(()) } From c15ac3311505546a2c37785c21912a6b2a7de2ae Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Wed, 4 Sep 2024 16:20:47 +0100 Subject: [PATCH 33/35] chore(release): release candidate 2024.09.1.3 ================== Crate Versions ================== sn_auditor: 0.3.0-rc.3 sn_build_info: 0.1.12-rc.3 sn_cli: 0.95.0-rc.3 sn_client: 0.110.0-rc.3 sn_faucet: 0.5.0-rc.3 sn_logging: 0.2.33-rc.3 sn_metrics: 0.1.13-rc.3 nat-detection: 0.2.3-rc.3 sn_networking: 0.18.0-rc.3 sn_node: 0.111.0-rc.3 node-launchpad: 0.3.14-rc.3 sn_node_manager: 0.10.3-rc.3 sn_node_rpc_client: 0.6.28-rc.3 sn_peers_acquisition: 0.5.0-rc.3 sn_protocol: 0.17.8-rc.3 sn_registers: 0.3.18-rc.3 sn_service_management: 0.3.11-rc.3 sn_transfers: 0.19.0-rc.3 test_utils: 0.4.4-rc.3 token_supplies: 0.1.51-rc.3 =================== Binary Versions =================== faucet: 0.5.0-rc.3 nat-detection: 0.2.3-rc.3 node-launchpad: 0.3.14-rc.3 safe: 0.95.0-rc.3 safenode: 0.111.0-rc.3 safenode-manager: 0.10.3-rc.3 safenode_rpc_client: 0.6.28-rc.3 safenodemand: 0.10.3-rc.3 sn_auditor: 0.3.0-rc.3 --- Cargo.lock | 40 ++++++++++++++++---------------- nat-detection/Cargo.toml | 4 ++-- node-launchpad/Cargo.toml | 8 +++---- release-cycle-info | 2 +- sn_auditor/Cargo.toml | 8 +++---- sn_build_info/Cargo.toml | 2 +- sn_cli/Cargo.toml | 14 +++++------ sn_client/Cargo.toml | 18 +++++++------- sn_faucet/Cargo.toml | 16 ++++++------- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 10 ++++---- sn_node/Cargo.toml | 24 +++++++++---------- sn_node_manager/Cargo.toml | 12 +++++----- sn_node_rpc_client/Cargo.toml | 16 ++++++------- sn_peers_acquisition/Cargo.toml | 4 ++-- sn_protocol/Cargo.toml | 8 +++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++---- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 2 +- token_supplies/Cargo.toml | 2 +- 22 files changed, 103 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1aa0e7b690..65d1357650 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4576,7 +4576,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.3-rc.2" +version = "0.2.3-rc.3" dependencies = [ "clap", "clap-verbosity-flag", @@ -4691,7 +4691,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.3.14-rc.2" +version = "0.3.14-rc.3" dependencies = [ "ansi-to-tui", "atty", @@ -6941,7 +6941,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.10.3-rc.2" +version = "0.10.3-rc.3" dependencies = [ "assert_cmd", "assert_fs", @@ -7003,7 +7003,7 @@ dependencies = [ [[package]] name = "sn_auditor" -version = "0.3.0-rc.2" +version = "0.3.0-rc.3" dependencies = [ "blsttc", "clap", @@ -7037,14 +7037,14 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.12-rc.2" +version = "0.1.12-rc.3" dependencies = [ "vergen", ] [[package]] name = "sn_cli" -version = "0.95.0-rc.2" +version = "0.95.0-rc.3" dependencies = [ "aes 0.7.5", "base64 0.22.1", @@ -7086,7 +7086,7 @@ dependencies = [ [[package]] name = "sn_client" -version = "0.110.0-rc.2" +version = "0.110.0-rc.3" dependencies = [ "assert_matches", "async-trait", @@ -7169,7 +7169,7 @@ dependencies = [ [[package]] name = "sn_faucet" -version = "0.5.0-rc.2" +version = "0.5.0-rc.3" dependencies = [ "assert_fs", "base64 0.22.1", @@ -7201,7 +7201,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.33-rc.2" +version = "0.2.33-rc.3" dependencies = [ "chrono", "color-eyre", @@ -7226,7 +7226,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.13-rc.2" +version = "0.1.13-rc.3" dependencies = [ "clap", "color-eyre", @@ -7240,7 +7240,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.18.0-rc.2" +version = "0.18.0-rc.3" dependencies = [ "aes-gcm-siv", "async-trait", @@ -7283,7 +7283,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.111.0-rc.2" +version = "0.111.0-rc.3" dependencies = [ "assert_fs", "assert_matches", @@ -7337,7 +7337,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.28-rc.2" +version = "0.6.28-rc.3" dependencies = [ "assert_fs", "async-trait", @@ -7364,7 +7364,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.0-rc.2" +version = "0.5.0-rc.3" dependencies = [ "clap", "lazy_static", @@ -7380,7 +7380,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.8-rc.2" +version = "0.17.8-rc.3" dependencies = [ "blsttc", "bytes", @@ -7409,7 +7409,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.3.18-rc.2" +version = "0.3.18-rc.3" dependencies = [ "blsttc", "crdts", @@ -7426,7 +7426,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.3.11-rc.2" +version = "0.3.11-rc.3" dependencies = [ "async-trait", "dirs-next", @@ -7452,7 +7452,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.19.0-rc.2" +version = "0.19.0-rc.3" dependencies = [ "assert_fs", "blsttc", @@ -7795,7 +7795,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.4-rc.2" +version = "0.4.4-rc.3" dependencies = [ "color-eyre", "dirs-next", @@ -7927,7 +7927,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.51-rc.2" +version = "0.1.51-rc.3" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 1b1deb6e4e..8b978ad4d0 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.3-rc.2" +version = "0.2.3-rc.3" [[bin]] name = "nat-detection" @@ -28,7 +28,7 @@ libp2p = { version = "0.53", features = [ "macros", "upnp", ] } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.2" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.3" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index d65e856476..fc9d60dea0 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.3.14-rc.2" +version = "0.3.14-rc.3" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -48,10 +48,10 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn-node-manager = { version = "0.10.3-rc.2", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.0-rc.2", path = "../sn_peers_acquisition" } +sn-node-manager = { version = "0.10.3-rc.3", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.0-rc.3", path = "../sn_peers_acquisition" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.3.11-rc.2", path = "../sn_service_management" } +sn_service_management = { version = "0.3.11-rc.3", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/release-cycle-info b/release-cycle-info index f3989309f8..ef49747437 100644 --- a/release-cycle-info +++ b/release-cycle-info @@ -15,4 +15,4 @@ release-year: 2024 release-month: 09 release-cycle: 1 -release-cycle-counter: 2 +release-cycle-counter: 3 diff --git a/sn_auditor/Cargo.toml b/sn_auditor/Cargo.toml index 393bc8a72a..4f0590b0de 100644 --- a/sn_auditor/Cargo.toml +++ b/sn_auditor/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Network Auditor" name = "sn_auditor" -version = "0.3.0-rc.2" +version = "0.3.0-rc.3" edition = "2021" homepage = "https://maidsafe.net" repository = "https://github.com/maidsafe/safe_network" @@ -31,9 +31,9 @@ graphviz-rust = { version = "0.9.0", optional = true } lazy_static = "1.4.0" serde = { version = "1.0.133", features = ["derive", "rc"] } serde_json = "1.0.108" -sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } tiny_http = { version = "0.12", features = ["ssl-rustls"] } tracing = { version = "~0.1.26" } tokio = { version = "1.32.0", features = [ diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index 9a26f7a426..c946a7fe2b 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.12-rc.2" +version = "0.1.12-rc.3" [build-dependencies] vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } diff --git a/sn_cli/Cargo.toml b/sn_cli/Cargo.toml index 5ce908e59f..38d89e10db 100644 --- a/sn_cli/Cargo.toml +++ b/sn_cli/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_cli" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.95.0-rc.2" +version = "0.95.0-rc.3" [[bin]] path = "src/bin/main.rs" @@ -58,11 +58,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ rmp-serde = "1.1.1" rpassword = "7.3.1" serde = { version = "1.0.133", features = ["derive"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } -sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } tempfile = "3.6.0" tiny-keccak = "~2.0.2" tokio = { version = "1.32.0", features = [ @@ -84,7 +84,7 @@ eyre = "0.6.8" criterion = "0.5.1" tempfile = "3.6.0" rand = { version = "~0.8.5", features = ["small_rng"] } -sn_client = { path = "../sn_client", version = "0.110.0-rc.2", features = [ +sn_client = { path = "../sn_client", version = "0.110.0-rc.3", features = [ "test-utils", ] } diff --git a/sn_client/Cargo.toml b/sn_client/Cargo.toml index e6296eb900..7b2e6800ac 100644 --- a/sn_client/Cargo.toml +++ b/sn_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.110.0-rc.2" +version = "0.110.0-rc.3" [features] default = [] @@ -49,16 +49,16 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } tempfile = "3.6.0" thiserror = "1.0.23" tiny-keccak = "~2.0.2" tracing = { version = "~0.1.26" } xor_name = "5.0.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2", optional = true } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3", optional = true } eyre = { version = "0.6.8", optional = true } [dev-dependencies] @@ -67,8 +67,8 @@ dirs-next = "~2.0.0" # add rand to libp2p libp2p-identity = { version = "0.2.7", features = ["rand"] } sn_client = { path = "../sn_client", features = ["test-utils"] } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3", features = [ "test-utils", ] } @@ -83,7 +83,7 @@ crate-type = ["cdylib", "rlib"] getrandom = { version = "0.2.12", features = ["js"] } wasm-bindgen = "0.2.90" wasm-bindgen-futures = "0.4.40" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } console_error_panic_hook = "0.1.6" tracing-wasm = "0.2.1" wasmtimer = "0.2.0" diff --git a/sn_faucet/Cargo.toml b/sn_faucet/Cargo.toml index 7872b7e1e3..508e532cd9 100644 --- a/sn_faucet/Cargo.toml +++ b/sn_faucet/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_faucet" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.0-rc.2" +version = "0.5.0-rc.3" [features] default = ["gifting"] @@ -37,13 +37,13 @@ indicatif = { version = "0.17.5", features = ["tokio"] } minreq = { version = "2.11.0", features = ["https-rustls"], optional = true } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } -sn_cli = { path = "../sn_cli", version = "0.95.0-rc.2" } -sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } +sn_cli = { path = "../sn_cli", version = "0.95.0-rc.3" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } tokio = { version = "1.32.0", features = ["parking_lot", "rt"] } tracing = { version = "~0.1.26" } url = "2.5.0" diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 85e941665f..5c8018ecb4 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.33-rc.2" +version = "0.2.33-rc.3" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index a30cbe5d2d..dd1a80d9fe 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.13-rc.2" +version = "0.1.13-rc.3" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index 9d8e5fec0c..bb4181d8d1 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.18.0-rc.2" +version = "0.18.0-rc.3" [features] default = [] @@ -53,10 +53,10 @@ rand = { version = "~0.8.5", features = ["small_rng"] } rayon = "1.8.0" rmp-serde = "1.1.1" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path="../sn_build_info", version = "0.1.12-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } +sn_build_info = { path="../sn_build_info", version = "0.1.12-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index d0464269d9..b6a9b5297b 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.111.0-rc.2" +version = "0.111.0-rc.3" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -50,14 +50,14 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_networking = { path = "../sn_networking", version = "0.18.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.3" } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ "io-util", @@ -84,11 +84,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", features = [ +sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 26662fbc69..49d9ef8464 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.10.3-rc.2" +version = "0.10.3-rc.3" [[bin]] name = "safenode-manager" @@ -44,12 +44,12 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2" } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.2" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.3" } sn-releases = "0.2.6" -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index 19ae79b9f7..d917564d3e 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.28-rc.2" +version = "0.6.28-rc.3" [[bin]] name = "safenode_rpc_client" @@ -23,13 +23,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version="0.53", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_client = { path = "../sn_client", version = "0.110.0-rc.2" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_node = { path = "../sn_node", version = "0.111.0-rc.2" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_node = { path = "../sn_node", version = "0.111.0-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index 5300740b21..955841a297 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.0-rc.2" +version = "0.5.0-rc.3" [features] local-discovery = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version="0.53", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false} tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index 59b7c1f67b..68d1d8739c 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.8-rc.2" +version = "0.17.8-rc.3" [features] default = [] @@ -28,9 +28,9 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.2" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.2" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index 7edab34ab6..c959fdecaf 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.18-rc.2" +version = "0.3.18-rc.3" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index a4fd4bf1b1..dfd1d07053 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.11-rc.2" +version = "0.3.11-rc.3" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.2" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.2", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.2" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index d82594116a..effa8ce646 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.0-rc.2" +version = "0.19.0-rc.3" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index b3683f3448..670566c638 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.4-rc.2" +version = "0.4.4-rc.3" [dependencies] color-eyre = "~0.6.2" diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index 5798656b3c..000c12c639 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.51-rc.2" +version = "0.1.51-rc.3" [dependencies] From decc4fc4c864df95c95fb6bf0a04a61e8a088262 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Fri, 6 Sep 2024 20:16:20 +0100 Subject: [PATCH 34/35] docs: changelog for `2024.09.1.3` release --- CHANGELOG.md | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b5160c157..913d5eecda 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,72 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 *When editing this file, please respect a line length of 100.* +## 2024-09-09 + +### Network + +#### Added + +- More logging for storage errors and setting the responsible range. + +#### Changed + +- The node's store cost calculation has had various updates: + + The minimum and maximum were previously set to 10 and infinity. They've now been updated to 1 + and 1 million, respectively. + + We are now using a sigmoid curve, rather than a linear curve, as the base curve. The previous + curve only grew steep when the storage capacity was 40 to 60 percent. + + The overall calculation is simplified. +- We expect the updates to the store cost calculation to prevent 'lottery' payments, where one node + would have abnormally high earnings. +- The network version string, which is used when both nodes and clients connect to the network, now + uses the version number from the `sn_protocol` crate rather than `sn_networking`. This is a + breaking change in `sn_networking`. +- External address management is improved. Before, if anyone observed us at a certain public + IP+port, we would trust that and add it if it matches our local port. Now, we’re keeping track and + making sure we only have a single external address that we set when we’ve been observed as that + address a certain amount of times (3 by default). It should even handle cases where our IP changes + because of (mobile) roaming. +- The `Spend` network data type has been refactored to make it lighter and simpler. +- The entire transaction system has been redesigned; the code size and complexity have been reduced + by an order of magnitude. +- In addition, almost 10 types were removed from the transaction code, further reducing the + complexity. +- The internals of the `Transfer` and `CashNote` types have been reworked. +- The replication range has been reduced, which in turn reduces the base traffic for replication. + +### Client + +#### Fixed + +- Registers are fetched and merged correctly. + +### Launchpad + +#### Added + +- A connection mode feature enables users to select whether they want their nodes to connect to the + network using automatic NAT detection, upnp, home network, or custom port mappings in their + connection. Previously, the launchpad used NAT detection on the user’s behalf. By providing the + ability to explore more connection modes, hopefully this will get more users connected. + +#### Changed + +- On the drive selection dialog, drives to which the user does not have read or write access are + marked as such. + +### Documentation + +#### Added + +- A README was provided for the `sn_registers` crate. It intends to give a comprehensive + understanding of the register data type and how it can be used by developers. + +#### Changed + +- Provided more information on connecting to the network using the four keys related to funds, fees + and royalties. + ## 2024-09-02 ### Launchpad From 114adcb34a2c962afa88723c22faa282e87bef71 Mon Sep 17 00:00:00 2001 From: Chris O'Neil Date: Sun, 8 Sep 2024 18:22:00 +0100 Subject: [PATCH 35/35] chore(release): stable release 2024.09.1.3 ================== Crate Versions ================== sn_auditor: 0.3.0 sn_build_info: 0.1.12 sn_cli: 0.95.0 sn_client: 0.110.0 sn_faucet: 0.5.0 sn_logging: 0.2.33 sn_metrics: 0.1.13 nat-detection: 0.2.3 sn_networking: 0.18.0 sn_node: 0.111.0 node-launchpad: 0.3.14 sn_node_manager: 0.10.3 sn_node_rpc_client: 0.6.28 sn_peers_acquisition: 0.5.0 sn_protocol: 0.17.8 sn_registers: 0.3.18 sn_service_management: 0.3.11 sn_transfers: 0.19.0 test_utils: 0.4.4 token_supplies: 0.1.51 =================== Binary Versions =================== faucet: 0.5.0 nat-detection: 0.2.3 node-launchpad: 0.3.14 safe: 0.95.0 safenode: 0.111.0 safenode-manager: 0.10.3 safenode_rpc_client: 0.6.28 safenodemand: 0.10.3 sn_auditor: 0.3.0 --- Cargo.lock | 40 ++++++++++++++++---------------- nat-detection/Cargo.toml | 4 ++-- node-launchpad/Cargo.toml | 8 +++---- sn_auditor/Cargo.toml | 8 +++---- sn_build_info/Cargo.toml | 2 +- sn_cli/Cargo.toml | 14 +++++------ sn_client/Cargo.toml | 18 +++++++------- sn_faucet/Cargo.toml | 16 ++++++------- sn_logging/Cargo.toml | 2 +- sn_metrics/Cargo.toml | 2 +- sn_networking/Cargo.toml | 10 ++++---- sn_node/Cargo.toml | 24 +++++++++---------- sn_node_manager/Cargo.toml | 12 +++++----- sn_node_rpc_client/Cargo.toml | 16 ++++++------- sn_peers_acquisition/Cargo.toml | 4 ++-- sn_protocol/Cargo.toml | 8 +++---- sn_registers/Cargo.toml | 2 +- sn_service_management/Cargo.toml | 8 +++---- sn_transfers/Cargo.toml | 2 +- test_utils/Cargo.toml | 2 +- token_supplies/Cargo.toml | 2 +- 21 files changed, 102 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 65d1357650..efc70c9b1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4576,7 +4576,7 @@ dependencies = [ [[package]] name = "nat-detection" -version = "0.2.3-rc.3" +version = "0.2.3" dependencies = [ "clap", "clap-verbosity-flag", @@ -4691,7 +4691,7 @@ dependencies = [ [[package]] name = "node-launchpad" -version = "0.3.14-rc.3" +version = "0.3.14" dependencies = [ "ansi-to-tui", "atty", @@ -6941,7 +6941,7 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "sn-node-manager" -version = "0.10.3-rc.3" +version = "0.10.3" dependencies = [ "assert_cmd", "assert_fs", @@ -7003,7 +7003,7 @@ dependencies = [ [[package]] name = "sn_auditor" -version = "0.3.0-rc.3" +version = "0.3.0" dependencies = [ "blsttc", "clap", @@ -7037,14 +7037,14 @@ dependencies = [ [[package]] name = "sn_build_info" -version = "0.1.12-rc.3" +version = "0.1.12" dependencies = [ "vergen", ] [[package]] name = "sn_cli" -version = "0.95.0-rc.3" +version = "0.95.0" dependencies = [ "aes 0.7.5", "base64 0.22.1", @@ -7086,7 +7086,7 @@ dependencies = [ [[package]] name = "sn_client" -version = "0.110.0-rc.3" +version = "0.110.0" dependencies = [ "assert_matches", "async-trait", @@ -7169,7 +7169,7 @@ dependencies = [ [[package]] name = "sn_faucet" -version = "0.5.0-rc.3" +version = "0.5.0" dependencies = [ "assert_fs", "base64 0.22.1", @@ -7201,7 +7201,7 @@ dependencies = [ [[package]] name = "sn_logging" -version = "0.2.33-rc.3" +version = "0.2.33" dependencies = [ "chrono", "color-eyre", @@ -7226,7 +7226,7 @@ dependencies = [ [[package]] name = "sn_metrics" -version = "0.1.13-rc.3" +version = "0.1.13" dependencies = [ "clap", "color-eyre", @@ -7240,7 +7240,7 @@ dependencies = [ [[package]] name = "sn_networking" -version = "0.18.0-rc.3" +version = "0.18.0" dependencies = [ "aes-gcm-siv", "async-trait", @@ -7283,7 +7283,7 @@ dependencies = [ [[package]] name = "sn_node" -version = "0.111.0-rc.3" +version = "0.111.0" dependencies = [ "assert_fs", "assert_matches", @@ -7337,7 +7337,7 @@ dependencies = [ [[package]] name = "sn_node_rpc_client" -version = "0.6.28-rc.3" +version = "0.6.28" dependencies = [ "assert_fs", "async-trait", @@ -7364,7 +7364,7 @@ dependencies = [ [[package]] name = "sn_peers_acquisition" -version = "0.5.0-rc.3" +version = "0.5.0" dependencies = [ "clap", "lazy_static", @@ -7380,7 +7380,7 @@ dependencies = [ [[package]] name = "sn_protocol" -version = "0.17.8-rc.3" +version = "0.17.8" dependencies = [ "blsttc", "bytes", @@ -7409,7 +7409,7 @@ dependencies = [ [[package]] name = "sn_registers" -version = "0.3.18-rc.3" +version = "0.3.18" dependencies = [ "blsttc", "crdts", @@ -7426,7 +7426,7 @@ dependencies = [ [[package]] name = "sn_service_management" -version = "0.3.11-rc.3" +version = "0.3.11" dependencies = [ "async-trait", "dirs-next", @@ -7452,7 +7452,7 @@ dependencies = [ [[package]] name = "sn_transfers" -version = "0.19.0-rc.3" +version = "0.19.0" dependencies = [ "assert_fs", "blsttc", @@ -7795,7 +7795,7 @@ checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" [[package]] name = "test_utils" -version = "0.4.4-rc.3" +version = "0.4.4" dependencies = [ "color-eyre", "dirs-next", @@ -7927,7 +7927,7 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "token_supplies" -version = "0.1.51-rc.3" +version = "0.1.51" dependencies = [ "dirs-next", "reqwest 0.11.27", diff --git a/nat-detection/Cargo.toml b/nat-detection/Cargo.toml index 8b978ad4d0..f212b4ebd2 100644 --- a/nat-detection/Cargo.toml +++ b/nat-detection/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "nat-detection" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.3-rc.3" +version = "0.2.3" [[bin]] name = "nat-detection" @@ -28,7 +28,7 @@ libp2p = { version = "0.53", features = [ "macros", "upnp", ] } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.3" } +sn_networking = { path = "../sn_networking", version = "0.18.0" } tokio = { version = "1.32.0", features = ["full"] } tracing = { version = "~0.1.26" } tracing-log = "0.2.0" diff --git a/node-launchpad/Cargo.toml b/node-launchpad/Cargo.toml index fc9d60dea0..8c92a39f62 100644 --- a/node-launchpad/Cargo.toml +++ b/node-launchpad/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Node Launchpad" name = "node-launchpad" -version = "0.3.14-rc.3" +version = "0.3.14" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -48,10 +48,10 @@ reqwest = { version = "0.12.2", default-features = false, features = [ serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.107" signal-hook = "0.3.17" -sn-node-manager = { version = "0.10.3-rc.3", path = "../sn_node_manager" } -sn_peers_acquisition = { version = "0.5.0-rc.3", path = "../sn_peers_acquisition" } +sn-node-manager = { version = "0.10.3", path = "../sn_node_manager" } +sn_peers_acquisition = { version = "0.5.0", path = "../sn_peers_acquisition" } sn-releases = "~0.2.6" -sn_service_management = { version = "0.3.11-rc.3", path = "../sn_service_management" } +sn_service_management = { version = "0.3.11", path = "../sn_service_management" } strip-ansi-escapes = "0.2.0" strum = { version = "0.26.1", features = ["derive"] } sysinfo = "0.30.12" diff --git a/sn_auditor/Cargo.toml b/sn_auditor/Cargo.toml index 4f0590b0de..387233aee5 100644 --- a/sn_auditor/Cargo.toml +++ b/sn_auditor/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Network Auditor" name = "sn_auditor" -version = "0.3.0-rc.3" +version = "0.3.0" edition = "2021" homepage = "https://maidsafe.net" repository = "https://github.com/maidsafe/safe_network" @@ -31,9 +31,9 @@ graphviz-rust = { version = "0.9.0", optional = true } lazy_static = "1.4.0" serde = { version = "1.0.133", features = ["derive", "rc"] } serde_json = "1.0.108" -sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_client = { path = "../sn_client", version = "0.110.0" } +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } tiny_http = { version = "0.12", features = ["ssl-rustls"] } tracing = { version = "~0.1.26" } tokio = { version = "1.32.0", features = [ diff --git a/sn_build_info/Cargo.toml b/sn_build_info/Cargo.toml index c946a7fe2b..b47bdf68d0 100644 --- a/sn_build_info/Cargo.toml +++ b/sn_build_info/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_build_info" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.12-rc.3" +version = "0.1.12" [build-dependencies] vergen = { version = "8.0.0", features = ["build", "git", "gitcl"] } diff --git a/sn_cli/Cargo.toml b/sn_cli/Cargo.toml index 38d89e10db..10022e2ff6 100644 --- a/sn_cli/Cargo.toml +++ b/sn_cli/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_cli" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.95.0-rc.3" +version = "0.95.0" [[bin]] path = "src/bin/main.rs" @@ -58,11 +58,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ rmp-serde = "1.1.1" rpassword = "7.3.1" serde = { version = "1.0.133", features = ["derive"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } -sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12" } +sn_client = { path = "../sn_client", version = "0.110.0" } +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8" } tempfile = "3.6.0" tiny-keccak = "~2.0.2" tokio = { version = "1.32.0", features = [ @@ -84,7 +84,7 @@ eyre = "0.6.8" criterion = "0.5.1" tempfile = "3.6.0" rand = { version = "~0.8.5", features = ["small_rng"] } -sn_client = { path = "../sn_client", version = "0.110.0-rc.3", features = [ +sn_client = { path = "../sn_client", version = "0.110.0", features = [ "test-utils", ] } diff --git a/sn_client/Cargo.toml b/sn_client/Cargo.toml index 7b2e6800ac..c6209ea077 100644 --- a/sn_client/Cargo.toml +++ b/sn_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.110.0-rc.3" +version = "0.110.0" [features] default = [] @@ -49,16 +49,16 @@ rayon = "1.8.0" rmp-serde = "1.1.1" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_networking = { path = "../sn_networking", version = "0.18.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8" } +sn_registers = { path = "../sn_registers", version = "0.3.18" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } tempfile = "3.6.0" thiserror = "1.0.23" tiny-keccak = "~2.0.2" tracing = { version = "~0.1.26" } xor_name = "5.0.0" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3", optional = true } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0", optional = true } eyre = { version = "0.6.8", optional = true } [dev-dependencies] @@ -67,8 +67,8 @@ dirs-next = "~2.0.0" # add rand to libp2p libp2p-identity = { version = "0.2.7", features = ["rand"] } sn_client = { path = "../sn_client", features = ["test-utils"] } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_registers = { path = "../sn_registers", version = "0.3.18", features = [ "test-utils", ] } @@ -83,7 +83,7 @@ crate-type = ["cdylib", "rlib"] getrandom = { version = "0.2.12", features = ["js"] } wasm-bindgen = "0.2.90" wasm-bindgen-futures = "0.4.40" -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } console_error_panic_hook = "0.1.6" tracing-wasm = "0.2.1" wasmtimer = "0.2.0" diff --git a/sn_faucet/Cargo.toml b/sn_faucet/Cargo.toml index 508e532cd9..a82ff0ed2a 100644 --- a/sn_faucet/Cargo.toml +++ b/sn_faucet/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_faucet" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.0-rc.3" +version = "0.5.0" [features] default = ["gifting"] @@ -37,13 +37,13 @@ indicatif = { version = "0.17.5", features = ["tokio"] } minreq = { version = "2.11.0", features = ["https-rustls"], optional = true } serde = { version = "1.0.193", features = ["derive"] } serde_json = "1.0.108" -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } -sn_cli = { path = "../sn_cli", version = "0.95.0-rc.3" } -sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12" } +sn_cli = { path = "../sn_cli", version = "0.95.0" } +sn_client = { path = "../sn_client", version = "0.110.0" } +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } tokio = { version = "1.32.0", features = ["parking_lot", "rt"] } tracing = { version = "~0.1.26" } url = "2.5.0" diff --git a/sn_logging/Cargo.toml b/sn_logging/Cargo.toml index 5c8018ecb4..7a2decb882 100644 --- a/sn_logging/Cargo.toml +++ b/sn_logging/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_logging" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.2.33-rc.3" +version = "0.2.33" [dependencies] chrono = "~0.4.19" diff --git a/sn_metrics/Cargo.toml b/sn_metrics/Cargo.toml index dd1a80d9fe..daa0726e94 100644 --- a/sn_metrics/Cargo.toml +++ b/sn_metrics/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_metrics" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.13-rc.3" +version = "0.1.13" [[bin]] path = "src/main.rs" diff --git a/sn_networking/Cargo.toml b/sn_networking/Cargo.toml index bb4181d8d1..2641c78c5c 100644 --- a/sn_networking/Cargo.toml +++ b/sn_networking/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_networking" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.18.0-rc.3" +version = "0.18.0" [features] default = [] @@ -53,10 +53,10 @@ rand = { version = "~0.8.5", features = ["small_rng"] } rayon = "1.8.0" rmp-serde = "1.1.1" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path="../sn_build_info", version = "0.1.12-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } +sn_build_info = { path="../sn_build_info", version = "0.1.12" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } +sn_registers = { path = "../sn_registers", version = "0.3.18" } sysinfo = { version = "0.30.8", default-features = false, optional = true } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = ["sha3"] } diff --git a/sn_node/Cargo.toml b/sn_node/Cargo.toml index b6a9b5297b..c598fbad39 100644 --- a/sn_node/Cargo.toml +++ b/sn_node/Cargo.toml @@ -2,7 +2,7 @@ authors = ["MaidSafe Developers "] description = "Safe Node" name = "sn_node" -version = "0.111.0-rc.3" +version = "0.111.0" edition = "2021" license = "GPL-3.0" homepage = "https://maidsafe.net" @@ -50,14 +50,14 @@ rmp-serde = "1.1.1" rayon = "1.8.0" self_encryption = "~0.29.0" serde = { version = "1.0.133", features = ["derive", "rc"] } -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_networking = { path = "../sn_networking", version = "0.18.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_networking = { path = "../sn_networking", version = "0.18.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8" } +sn_registers = { path = "../sn_registers", version = "0.3.18" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11" } thiserror = "1.0.23" tokio = { version = "1.32.0", features = [ "io-util", @@ -84,11 +84,11 @@ reqwest = { version = "0.12.2", default-features = false, features = [ "rustls-tls-manual-roots", ] } serde_json = "1.0" -sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", features = [ +sn_client = { path = "../sn_client", version = "0.110.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3", features = [ +sn_transfers = { path = "../sn_transfers", version = "0.19.0", features = [ "test-utils", ] } tempfile = "3.6.0" diff --git a/sn_node_manager/Cargo.toml b/sn_node_manager/Cargo.toml index 49d9ef8464..80a8f02f17 100644 --- a/sn_node_manager/Cargo.toml +++ b/sn_node_manager/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn-node-manager" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.10.3-rc.3" +version = "0.10.3" [[bin]] name = "safenode-manager" @@ -44,12 +44,12 @@ semver = "1.0.20" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3" } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.3" } +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8" } +sn_service_management = { path = "../sn_service_management", version = "0.3.11" } sn-releases = "0.2.6" -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.26", features = ["full"] } diff --git a/sn_node_rpc_client/Cargo.toml b/sn_node_rpc_client/Cargo.toml index d917564d3e..3e6bc323fa 100644 --- a/sn_node_rpc_client/Cargo.toml +++ b/sn_node_rpc_client/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_node_rpc_client" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.6.28-rc.3" +version = "0.6.28" [[bin]] name = "safenode_rpc_client" @@ -23,13 +23,13 @@ color-eyre = "0.6.2" hex = "~0.4.3" libp2p = { version="0.53", features = ["kad"]} libp2p-identity = { version="0.2.7", features = ["rand"] } -sn_client = { path = "../sn_client", version = "0.110.0-rc.3" } -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_node = { path = "../sn_node", version = "0.111.0-rc.3" } -sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", features=["rpc"] } -sn_service_management = { path = "../sn_service_management", version = "0.3.11-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_client = { path = "../sn_client", version = "0.110.0" } +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_node = { path = "../sn_node", version = "0.111.0" } +sn_peers_acquisition = { path = "../sn_peers_acquisition", version = "0.5.0" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8", features=["rpc"] } +sn_service_management = { path = "../sn_service_management", version = "0.3.11" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } thiserror = "1.0.23" # # watch out updating this, protoc compiler needs to be installed on all build systems # # arm builds + musl are very problematic diff --git a/sn_peers_acquisition/Cargo.toml b/sn_peers_acquisition/Cargo.toml index 955841a297..ebd44cbef9 100644 --- a/sn_peers_acquisition/Cargo.toml +++ b/sn_peers_acquisition/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_peers_acquisition" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.5.0-rc.3" +version = "0.5.0" [features] local-discovery = [] @@ -21,7 +21,7 @@ lazy_static = "~1.4.0" libp2p = { version="0.53", features = [] } rand = "0.8.5" reqwest = { version="0.12.2", default-features=false, features = ["rustls-tls"] } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", optional = true} +sn_protocol = { path = "../sn_protocol", version = "0.17.8", optional = true} thiserror = "1.0.23" tokio = { version = "1.32.0", default-features = false} tracing = { version = "~0.1.26" } diff --git a/sn_protocol/Cargo.toml b/sn_protocol/Cargo.toml index 68d1d8739c..91feb1a370 100644 --- a/sn_protocol/Cargo.toml +++ b/sn_protocol/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_protocol" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.17.8-rc.3" +version = "0.17.8" [features] default = [] @@ -28,9 +28,9 @@ rmp-serde = "1.1.1" serde = { version = "1.0.133", features = [ "derive", "rc" ]} serde_json = "1.0" sha2 = "0.10.7" -sn_build_info = { path = "../sn_build_info", version = "0.1.12-rc.3" } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } -sn_registers = { path = "../sn_registers", version = "0.3.18-rc.3" } +sn_build_info = { path = "../sn_build_info", version = "0.1.12" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } +sn_registers = { path = "../sn_registers", version = "0.3.18" } thiserror = "1.0.23" tiny-keccak = { version = "~2.0.2", features = [ "sha3" ] } tracing = { version = "~0.1.26" } diff --git a/sn_registers/Cargo.toml b/sn_registers/Cargo.toml index c959fdecaf..15effbce1f 100644 --- a/sn_registers/Cargo.toml +++ b/sn_registers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_registers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.18-rc.3" +version = "0.3.18" [features] test-utils = [] diff --git a/sn_service_management/Cargo.toml b/sn_service_management/Cargo.toml index dfd1d07053..e09c63fe53 100644 --- a/sn_service_management/Cargo.toml +++ b/sn_service_management/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "sn_service_management" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.3.11-rc.3" +version = "0.3.11" [dependencies] async-trait = "0.1" @@ -19,11 +19,11 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" semver = "1.0.20" service-manager = "0.7.0" -sn_logging = { path = "../sn_logging", version = "0.2.33-rc.3" } -sn_protocol = { path = "../sn_protocol", version = "0.17.8-rc.3", features = [ +sn_logging = { path = "../sn_logging", version = "0.2.33" } +sn_protocol = { path = "../sn_protocol", version = "0.17.8", features = [ "rpc", ] } -sn_transfers = { path = "../sn_transfers", version = "0.19.0-rc.3" } +sn_transfers = { path = "../sn_transfers", version = "0.19.0" } sysinfo = "0.30.12" thiserror = "1.0.23" tokio = { version = "1.32.0", features = ["time"] } diff --git a/sn_transfers/Cargo.toml b/sn_transfers/Cargo.toml index effa8ce646..20767d938c 100644 --- a/sn_transfers/Cargo.toml +++ b/sn_transfers/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "sn_transfers" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.19.0-rc.3" +version = "0.19.0" [features] reward-forward = [] diff --git a/test_utils/Cargo.toml b/test_utils/Cargo.toml index 670566c638..9642cd6e56 100644 --- a/test_utils/Cargo.toml +++ b/test_utils/Cargo.toml @@ -7,7 +7,7 @@ license = "GPL-3.0" name = "test_utils" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.4.4-rc.3" +version = "0.4.4" [dependencies] color-eyre = "~0.6.2" diff --git a/token_supplies/Cargo.toml b/token_supplies/Cargo.toml index 000c12c639..f8c1b0da8e 100644 --- a/token_supplies/Cargo.toml +++ b/token_supplies/Cargo.toml @@ -8,7 +8,7 @@ license = "GPL-3.0" name = "token_supplies" readme = "README.md" repository = "https://github.com/maidsafe/safe_network" -version = "0.1.51-rc.3" +version = "0.1.51" [dependencies]