From 719e28488f44a349bdc5b1edf86399db48fa273a Mon Sep 17 00:00:00 2001 From: ardocrat Date: Thu, 29 Jun 2023 23:52:30 +0300 Subject: [PATCH] config: optimize access to node config members, fix check for port availability --- locales/en.yml | 1 + locales/ru.yml | 1 + src/gui/views/network.rs | 10 ---- src/gui/views/network_mining.rs | 8 +-- src/gui/views/settings_node.rs | 46 ++++++++--------- src/gui/views/settings_stratum.rs | 26 +++------- src/gui/views/views.rs | 2 +- src/node/config.rs | 71 +++++++++++++++++++++----- src/node/node.rs | 83 +++++++++++++++++++++++++++---- 9 files changed, 162 insertions(+), 86 deletions(-) diff --git a/locales/en.yml b/locales/en.yml index 5862040..4b1ebbe 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -76,6 +76,7 @@ network_settings: enter_value: Enter value port_unavailable: Specified port is unavailable restart_app_required: App restart is required to apply changes. + restart_node_required: Node server restart is required to apply changes. enable: Enable disable: Disable restart: Restart diff --git a/locales/ru.yml b/locales/ru.yml index e902d1c..4662c91 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -76,6 +76,7 @@ network_settings: enter_value: Введите значение port_unavailable: Указанный порт недоступен restart_app_required: Для применения изменений требуется перезапуск приложения. + restart_node_required: Для применения изменений требуется перезапуск узла. enable: Включить disable: Выключить restart: Перезапустить diff --git a/src/gui/views/network.rs b/src/gui/views/network.rs index a8b9329..7005907 100644 --- a/src/gui/views/network.rs +++ b/src/gui/views/network.rs @@ -337,15 +337,5 @@ impl Network { ui.add_space(6.0); }); } - - /// Check whether a port is available on the provided host. - pub fn is_port_available(host: &String, port: &String) -> bool { - if let Ok(p) = port.parse::() { - let ip_addr = Ipv4Addr::from_str(host.as_str()).unwrap(); - let ipv4 = SocketAddrV4::new(ip_addr, p); - return TcpListener::bind(ipv4).is_ok(); - } - false - } } diff --git a/src/gui/views/network_mining.rs b/src/gui/views/network_mining.rs index 45f7ad6..569dc13 100644 --- a/src/gui/views/network_mining.rs +++ b/src/gui/views/network_mining.rs @@ -113,13 +113,9 @@ impl NetworkTab for NetworkMining { }); columns[1].vertical_centered(|ui| { //TODO: Stratum mining wallet listening address. Replace with local wallet name. - let wallet_address = Settings::node_config_to_read() - .members.clone() - .server.stratum_mining_config.unwrap() - .wallet_listener_url - .replace("http://", ""); + let wallet_addr = NodeConfig::get_stratum_wallet_addr().replace("http://", ""); View::rounded_box(ui, - wallet_address, + wallet_addr, t!("network_mining.rewards_wallet"), [false, true, false, true]); }); diff --git a/src/gui/views/settings_node.rs b/src/gui/views/settings_node.rs index 470ed0b..221431e 100644 --- a/src/gui/views/settings_node.rs +++ b/src/gui/views/settings_node.rs @@ -44,7 +44,7 @@ pub struct NodeSetup { impl Default for NodeSetup { fn default() -> Self { let (api_ip, api_port) = NodeConfig::get_api_address_port(); - let is_api_port_available = is_api_port_available(&api_ip, &api_port); + let is_api_port_available = NodeConfig::is_api_port_available(&api_ip, &api_port); Self { api_port_edit: api_port, api_port_available_edit: is_api_port_available, @@ -127,8 +127,13 @@ impl NodeSetup { // Show API IP addresses to select. let (api_ip, api_port) = NodeConfig::get_api_address_port(); Network::ip_list_ui(ui, &api_ip, &addrs, |selected_ip| { - self.is_api_port_available = is_api_port_available(selected_ip, &api_port); + println!("12345 selected_ip {}", selected_ip); + let api_available = NodeConfig::is_api_port_available(selected_ip, &api_port); + println!("12345 selected_ip is_api_port_available {}", api_available); + self.is_api_port_available = api_available; + println!("12345 before save"); NodeConfig::save_api_address_port(selected_ip, &api_port); + println!("12345 after save"); }); ui.label(RichText::new(t!("network_settings.api_port")) @@ -161,14 +166,21 @@ impl NodeSetup { Navigator::show_modal(port_modal); cb.show_keyboard(); }); - ui.add_space(14.0); + ui.add_space(6.0); - // Show error when API server port is unavailable. if !self.is_api_port_available { + // Show error when API server port is unavailable. ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(16.0) .color(Colors::RED)); - ui.add_space(12.0); + ui.add_space(6.0); + } else if Node::is_running() { + // Show reminder to restart node if settings are changed. + ui.label(RichText::new(t!("network_settings.restart_node_required")) + .size(16.0) + .color(Colors::INACTIVE_TEXT) + ); + ui.add_space(6.0); } } @@ -221,7 +233,10 @@ impl NodeSetup { View::button(ui, t!("modal.save"), Colors::WHITE, || { // Check if port is available. let (ip, _) = NodeConfig::get_api_address_port(); - let available = is_api_port_available(&ip, &self.api_port_edit); + let available = NodeConfig::is_api_port_available( + &ip, + &self.api_port_edit + ); self.api_port_available_edit = available; if self.api_port_available_edit { @@ -242,23 +257,4 @@ impl NodeSetup { }); }); } -} - -fn is_api_port_available(ip: &String, port: &String) -> bool { - let same_address_as_running = { - let (current_ip, current_port) = NodeConfig::get_api_address_port(); - Node::is_running() && ¤t_ip == ip && ¤t_port == port - }; - - if same_address_as_running || (!Node::is_running() && Network::is_port_available(&ip, &port)) { - if &NodeConfig::get_p2p_port().to_string() != port { - let (stratum_ip, stratum_port) = NodeConfig::get_stratum_address_port(); - return if &stratum_ip == ip { - &stratum_port != port - } else { - true - } - } - } - false } \ No newline at end of file diff --git a/src/gui/views/settings_stratum.rs b/src/gui/views/settings_stratum.rs index f944b39..d2df645 100644 --- a/src/gui/views/settings_stratum.rs +++ b/src/gui/views/settings_stratum.rs @@ -38,7 +38,7 @@ pub struct StratumServerSetup { impl Default for StratumServerSetup { fn default() -> Self { let (ip, port) = NodeConfig::get_stratum_address_port(); - let is_port_available = is_stratum_port_available(&ip, &port); + let is_port_available = NodeConfig::is_stratum_port_available(&ip, &port); Self { stratum_port_edit: port, stratum_port_available_edit: is_port_available, @@ -72,11 +72,8 @@ impl StratumServerSetup { // Show stratum IP addresses to select. let (ip, port) = NodeConfig::get_stratum_address_port(); Network::ip_list_ui(ui, &ip, &all_ips, |selected_ip| { - self.is_port_available = is_stratum_port_available(selected_ip, &port); + self.is_port_available = NodeConfig::is_stratum_port_available(selected_ip, &port); NodeConfig::save_stratum_address_port(selected_ip, &port); - if !self.is_port_available { - NodeConfig::disable_stratum_autorun(); - } }); ui.label(RichText::new(t!("network_settings.port")) @@ -169,7 +166,10 @@ impl StratumServerSetup { View::button(ui, t!("modal.save"), Colors::WHITE, || { // Check if port is available. let (ip, _) = NodeConfig::get_api_address_port(); - let available = is_stratum_port_available(&ip, &self.stratum_port_edit); + let available = NodeConfig::is_stratum_port_available( + &ip, + &self.stratum_port_edit + ); self.stratum_port_available_edit = available; // Save port at config if it's available. @@ -187,18 +187,4 @@ impl StratumServerSetup { }); }); } -} - -fn is_stratum_port_available(ip: &String, port: &String) -> bool { - if Network::is_port_available(&ip, &port) { - if &NodeConfig::get_p2p_port().to_string() != port { - let (api_ip, api_port) = NodeConfig::get_api_address_port(); - return if &api_ip == ip { - &api_port != port - } else { - true - } - } - } - false } \ No newline at end of file diff --git a/src/gui/views/views.rs b/src/gui/views/views.rs index 1dae7e4..51c88a5 100644 --- a/src/gui/views/views.rs +++ b/src/gui/views/views.rs @@ -70,7 +70,7 @@ impl View { ui.input_mut().pointer = PointerState::default(); } if drag_resp.drag_released() || drag_resp.clicked() { - return true + return true; } false } diff --git a/src/node/config.rs b/src/node/config.rs index a8d1844..2c622c3 100644 --- a/src/node/config.rs +++ b/src/node/config.rs @@ -14,7 +14,7 @@ use std::fs::File; use std::io::{BufRead, BufReader, Write}; -use std::net::IpAddr; +use std::net::{IpAddr, Ipv4Addr, SocketAddrV4, TcpListener}; use std::str::FromStr; use grin_config::{config, ConfigError, ConfigMembers, GlobalConfig}; @@ -24,6 +24,7 @@ use grin_p2p::msg::PeerAddrs; use grin_p2p::{PeerAddr, Seeding}; use grin_servers::common::types::ChainValidationMode; use serde::{Deserialize, Serialize}; +use crate::node::Node; use crate::Settings; @@ -69,6 +70,12 @@ impl NodeConfig { Settings::write_to_file(&self.members, config_path); } + /// Get node config values, requires to start node. + pub fn get_members() -> ConfigMembers { + let r_config = Settings::node_config_to_read(); + r_config.members.clone() + } + /// Check that the api secret files exist and are valid. fn check_api_secret_files( chain_type: &ChainTypes, @@ -84,6 +91,16 @@ impl NodeConfig { } } + /// Check whether a port is available on the provided host. + pub fn is_port_available(host: &String, port: &String) -> bool { + if let Ok(p) = port.parse::() { + let ip_addr = Ipv4Addr::from_str(host.as_str()).unwrap(); + let ipv4 = SocketAddrV4::new(ip_addr, p); + return TcpListener::bind(ipv4).is_ok(); + } + false + } + /// Get stratum server IP address and port. pub fn get_stratum_address_port() -> (String, String) { let r_config = Settings::node_config_to_read(); @@ -114,6 +131,27 @@ impl NodeConfig { w_node_config.save(); } + /// Check if stratum server port is available across the system and config. + pub fn is_stratum_port_available(ip: &String, port: &String) -> bool { + if Self::is_port_available(&ip, &port) { + if &Self::get_p2p_port().to_string() != port { + let (api_ip, api_port) = Self::get_api_address_port(); + return if &api_ip == ip { + &api_port != port + } else { + true + } + } + } + false + } + + /// Get stratum mining server wallet address to get rewards. + pub fn get_stratum_wallet_addr() -> String { + let r_config = Settings::node_config_to_read(); + r_config.members.clone().server.stratum_mining_config.unwrap().wallet_listener_url + } + /// Check if stratum mining server autorun is enabled. pub fn is_stratum_autorun_enabled() -> bool { let stratum_config = Settings::node_config_to_read() @@ -141,18 +179,6 @@ impl NodeConfig { w_node_config.save(); } - /// Disable stratum mining server autorun. - pub fn disable_stratum_autorun() { - let mut w_node_config = Settings::node_config_to_update(); - w_node_config.members - .server - .stratum_mining_config - .as_mut() - .unwrap() - .enable_stratum_server = Some(false); - w_node_config.save(); - } - /// Get API server IP address and port. pub fn get_api_address_port() -> (String, String) { let r_config = Settings::node_config_to_read(); @@ -173,6 +199,25 @@ impl NodeConfig { w_node_config.save(); } + /// Check if api server port is available across the system and config. + pub fn is_api_port_available(ip: &String, port: &String) -> bool { + if Node::is_running() { + // Check if API server with same address is running. + let same_running = if let Some(running_addr) = Node::get_api_addr() { + running_addr == format!("{}:{}", ip, port) + } else { + false + }; + if same_running || NodeConfig::is_port_available(&ip, &port) { + return &NodeConfig::get_p2p_port().to_string() != port; + } + return false; + } else if NodeConfig::is_port_available(&ip, &port) { + return &NodeConfig::get_p2p_port().to_string() != port; + } + false + } + /// Get API secret text. pub fn get_api_secret() -> String { let r_config = Settings::node_config_to_read(); diff --git a/src/node/node.rs b/src/node/node.rs index 4d732da..ecfe55d 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -26,6 +26,7 @@ use grin_servers::{Server, ServerStats}; use grin_servers::common::types::Error; use jni::sys::{jboolean, jstring}; use lazy_static::lazy_static; +use crate::node::NodeConfig; use crate::Settings; @@ -38,6 +39,10 @@ lazy_static! { pub struct Node { /// Statistics data for UI. stats: Arc>>, + /// Running API server address. + api_addr: Arc>>, + /// Running P2P server port. + p2p_port: Arc>>, /// Indicator if server is starting. starting: AtomicBool, /// Thread flag to stop the server and start it again. @@ -56,6 +61,8 @@ impl Default for Node { fn default() -> Self { Self { stats: Arc::new(RwLock::new(None)), + api_addr: Arc::new(RwLock::new(None)), + p2p_port: Arc::new(RwLock::new(None)), starting: AtomicBool::new(false), restart_needed: AtomicBool::new(false), stop_needed: AtomicBool::new(false), @@ -89,6 +96,26 @@ impl Node { } } + /// Get API server address if node is running. + pub fn get_api_addr() -> Option { + let r_api_addr = NODE_STATE.api_addr.read().unwrap(); + if r_api_addr.is_some() { + Some(r_api_addr.as_ref().unwrap().clone()) + } else { + None + } + } + + /// Get P2P server port if node is running. + pub fn get_p2p_port() -> Option { + let r_p2p_port = NODE_STATE.p2p_port.read().unwrap(); + if r_p2p_port.is_some() { + Some(r_p2p_port.unwrap()) + } else { + None + } + } + /// Start stratum server. pub fn start_stratum_server() { NODE_STATE.start_stratum_server.store(true, Ordering::Relaxed); @@ -165,8 +192,9 @@ impl Node { NODE_STATE.restart_needed.store(false, Ordering::Relaxed); } Err(e) => { - Self::handle_init_error(&e); - return; + NODE_STATE.restart_needed.store(false, Ordering::Relaxed); + Self::on_start_error(&e); + break; } } } else if Self::is_stopping() { @@ -182,10 +210,21 @@ impl Node { NODE_STATE.starting.store(false, Ordering::Relaxed); NODE_STATE.stop_needed.store(false, Ordering::Relaxed); NODE_STATE.start_stratum_server.store(false, Ordering::Relaxed); + + // Clean launched API server address. + { + let mut w_api_addr = NODE_STATE.api_addr.write().unwrap(); + *w_api_addr = None; + } + // Clean launched P2P server port. + { + let mut w_p2p_port = NODE_STATE.p2p_port.write().unwrap(); + *w_p2p_port = None; + } break; } else { + // Start stratum mining server. if Self::is_stratum_server_starting() { - // Start mining server. let stratum_config = server .config .stratum_mining_config @@ -195,16 +234,14 @@ impl Node { // Wait for mining server to start and update status. thread::sleep(Duration::from_millis(100)); - NODE_STATE.start_stratum_server.store(false, Ordering::Relaxed); } - let stats = server.get_server_stats(); - if stats.is_ok() { - // Update server stats. + // Update server stats. + if let Ok(stats) = server.get_server_stats() { { let mut w_stats = NODE_STATE.stats.write().unwrap(); - *w_stats = Some(stats.as_ref().ok().unwrap().clone()); + *w_stats = Some(stats); } if first_start { @@ -217,14 +254,25 @@ impl Node { } } Err(e) => { - Self::handle_init_error(&e); + NODE_STATE.starting.store(false, Ordering::Relaxed); + Self::on_start_error(&e); } } }); } /// Handle node [`Server`] error on start. - fn handle_init_error(e: &Error) { + fn on_start_error(e: &Error) { + // Clean launched API server address. + { + let mut w_api_addr = NODE_STATE.api_addr.write().unwrap(); + *w_api_addr = None; + } + // Clean launched P2P server port. + { + let mut w_p2p_port = NODE_STATE.p2p_port.write().unwrap(); + *w_p2p_port = None; + } //TODO: Create error // NODE_STATE.init_error = Some(e); @@ -412,7 +460,7 @@ impl Node { /// Start the [`Server`] for node. fn start_server() -> Result { // Get current global config - let config = &Settings::node_config_to_read().members; + let config = NodeConfig::get_members(); let server_config = config.server.clone(); // Remove temporary file dir @@ -458,6 +506,19 @@ fn start_server() -> Result { let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) = Box::leak(Box::new(oneshot::channel::<()>())); + + // Write launching API server address. + { + let mut w_api_addr = NODE_STATE.api_addr.write().unwrap(); + *w_api_addr = Some(config.server.api_http_addr); + } + + // Write launching P2P server port. + { + let mut w_p2p_port = NODE_STATE.p2p_port.write().unwrap(); + *w_p2p_port = Some(config.server.p2p_config.port); + } + let server_result = Server::new(server_config.clone(), None, api_chan); server_result }