diff --git a/Cargo.lock b/Cargo.lock index 9be5b10..c03eceb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3794,6 +3794,7 @@ dependencies = [ "local-ip-address", "log", "openssl-sys", + "parking_lot 0.12.1", "qrcodegen", "rand 0.8.5", "rqrr", diff --git a/Cargo.toml b/Cargo.toml index 0c8556b..3d10cd3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,7 @@ futures = "0.3" dirs = "5.0.1" sys-locale = "0.3.0" chrono = "0.4.31" +parking_lot = "0.12.1" lazy_static = "1.4.0" toml = "0.8.2" serde = "1.0.170" diff --git a/locales/en.yml b/locales/en.yml index 933cca9..5975b45 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -183,6 +183,11 @@ network_node: data: Data size: Size (GB) peers: Peers + error_clean: Node data got corrupted, resync required. + resync: Resync + error_p2p_api: 'An error occurred during %{p2p_api} server initialization, check %{p2p_api} settings by selecting %{settings} at the bottom of the screen.' + error_config: 'An error occurred during configuration initialization, check settings by selecting %{settings} at the bottom of the screen.' + error_unknown: 'An error occurred during initialization, check integrated node settings by selecting %{settings} at the bottom of the screen or resync.' network_metrics: loading: Metrics will be available after the synchronization emission: Emission diff --git a/locales/ru.yml b/locales/ru.yml index 6081ad7..e4bd3a6 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -183,6 +183,11 @@ network_node: data: Данные size: Размер (ГБ) peers: Пиры + error_clean: Данные узла повреждены, необходима повторная синхронизация. + resync: Cинхронизация + error_p2p_api: 'Во время инициализации %{p2p_api} сервера произошла ошибка, проверьте настройки %{p2p_api}, выбрав %{settings} внизу экрана.' + error_config: 'Во время инициализации конфигурации произошла ошибка, проверьте настройки встроенного узла, выбрав %{settings} внизу экрана.' + error_unknown: 'Во время инициализации произошла ошибка, проверьте настройки встроенного узла, выбрав %{settings} внизу экрана или очистите данные.' network_metrics: loading: Показатели будут доступны после синхронизации emission: Эмиссия diff --git a/src/gui/views/network/content.rs b/src/gui/views/network/content.rs index 7d704a5..53a9365 100644 --- a/src/gui/views/network/content.rs +++ b/src/gui/views/network/content.rs @@ -13,15 +13,16 @@ // limitations under the License. use egui::{Margin, RichText, ScrollArea, Stroke}; +use grin_servers::common::types::Error; use crate::AppConfig; use crate::gui::Colors; -use crate::gui::icons::{BRIEFCASE, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, POWER}; +use crate::gui::icons::{ARROWS_COUNTER_CLOCKWISE, BRIEFCASE, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE, POWER}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{ConnectionsContent, NetworkMetrics, NetworkMining, NetworkNode, NetworkSettings, Root, TitlePanel, View}; use crate::gui::views::network::types::{NetworkTab, NetworkTabType}; use crate::gui::views::types::{TitleContentType, TitleType}; -use crate::node::Node; +use crate::node::{Node, NodeError}; use crate::wallet::ExternalConnection; /// Network content. @@ -267,4 +268,73 @@ impl NetworkContent { AppConfig::toggle_node_autostart(); }); } + + /// Draw integrated node error content. + pub fn node_error_ui(ui: &mut egui::Ui, e: NodeError) { + match e { + NodeError::Storage => { + View::center_content(ui, 156.0, |ui| { + ui.label(RichText::new(t!("network_node.error_clean")) + .size(16.0) + .color(Colors::RED) + ); + ui.add_space(8.0); + let btn_txt = format!("{} {}", + ARROWS_COUNTER_CLOCKWISE, + t!("network_node.resync")); + View::button(ui, btn_txt, Colors::GOLD, || { + Node::clean_up_data(); + Node::start(); + }); + ui.add_space(2.0); + }); + return; + } + NodeError::P2P | NodeError::API => { + let msg_type = match e { + NodeError::API => "API", + _ => "P2P" + }; + View::center_content(ui, 106.0, |ui| { + let text = t!( + "network_node.error_p2p_api", + "p2p_api" => msg_type, + "settings" => FADERS + ); + ui.label(RichText::new(text) + .size(16.0) + .color(Colors::RED) + ); + ui.add_space(2.0); + }); + return; + } + NodeError::Configuration => { + View::center_content(ui, 106.0, |ui| { + ui.label(RichText::new(t!("network_node.error_config", "settings" => FADERS)) + .size(16.0) + .color(Colors::RED) + ); + ui.add_space(2.0); + }); + } + NodeError::Unknown => { + View::center_content(ui, 156.0, |ui| { + ui.label(RichText::new(t!("network_node.error_unknown", "settings" => FADERS)) + .size(16.0) + .color(Colors::RED) + ); + ui.add_space(8.0); + let btn_txt = format!("{} {}", + ARROWS_COUNTER_CLOCKWISE, + t!("network_node.resync")); + View::button(ui, btn_txt, Colors::GOLD, || { + Node::clean_up_data(); + Node::start(); + }); + ui.add_space(2.0); + }); + } + } + } } \ No newline at end of file diff --git a/src/gui/views/network/metrics.rs b/src/gui/views/network/metrics.rs index 7453f3a..1d3ed29 100644 --- a/src/gui/views/network/metrics.rs +++ b/src/gui/views/network/metrics.rs @@ -36,7 +36,13 @@ impl NetworkTab for NetworkMetrics { } fn ui(&mut self, ui: &mut egui::Ui, _: &mut eframe::Frame, _: &dyn PlatformCallbacks) { - let server_stats = Node::get_stats(); + // Show an error content when available. + let node_err = Node::get_error(); + if node_err.is_some() { + NetworkContent::node_error_ui(ui, node_err.unwrap()); + return; + } + // Show message to enable node when it's not running. if !Node::is_running() { NetworkContent::disabled_node_ui(ui); @@ -50,6 +56,7 @@ impl NetworkTab for NetworkMetrics { } // Show message when metrics are not available. + let server_stats = Node::get_stats(); if server_stats.is_none() || Node::is_restarting() || server_stats.as_ref().unwrap().diff_stats.height == 0 { NetworkContent::loading_ui(ui, Some(t!("network_metrics.loading"))); diff --git a/src/gui/views/network/mining.rs b/src/gui/views/network/mining.rs index 812f6f3..dd6f1db 100644 --- a/src/gui/views/network/mining.rs +++ b/src/gui/views/network/mining.rs @@ -44,7 +44,12 @@ impl NetworkTab for NetworkMining { } fn ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame, cb: &dyn PlatformCallbacks) { - let server_stats = Node::get_stats(); + // Show an error content when available. + let node_err = Node::get_error(); + if node_err.is_some() { + NetworkContent::node_error_ui(ui, node_err.unwrap()); + return; + } // Show message to enable node when it's not running. if !Node::is_running() { @@ -59,6 +64,7 @@ impl NetworkTab for NetworkMining { } // Show message when mining is not available. + let server_stats = Node::get_stats(); if server_stats.is_none() || Node::is_restarting() || Node::get_sync_status().unwrap() != SyncStatus::NoSync { NetworkContent::loading_ui(ui, Some(t!("network_mining.loading"))); diff --git a/src/gui/views/network/node.rs b/src/gui/views/network/node.rs index 7ed5659..18c53ca 100644 --- a/src/gui/views/network/node.rs +++ b/src/gui/views/network/node.rs @@ -13,10 +13,11 @@ // limitations under the License. use egui::{RichText, Rounding, ScrollArea}; +use grin_servers::common::types::Error; use grin_servers::PeerStats; use crate::gui::Colors; -use crate::gui::icons::{AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS_CONNECTED, SHARE_NETWORK}; +use crate::gui::icons::{ARROWS_COUNTER_CLOCKWISE, AT, CUBE, DEVICES, FLOW_ARROW, HANDSHAKE, PACKAGE, PLUGS_CONNECTED, SHARE_NETWORK}; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{NetworkContent, Root, View}; use crate::gui::views::network::types::{NetworkTab, NetworkTabType}; @@ -32,7 +33,13 @@ impl NetworkTab for NetworkNode { } fn ui(&mut self, ui: &mut egui::Ui, _: &mut eframe::Frame, _: &dyn PlatformCallbacks) { - let server_stats = Node::get_stats(); + // Show an error content when available. + let node_err = Node::get_error(); + if node_err.is_some() { + NetworkContent::node_error_ui(ui, node_err.unwrap()); + return; + } + // Show message to enable node when it's not running. if !Node::is_running() { NetworkContent::disabled_node_ui(ui); @@ -40,6 +47,7 @@ impl NetworkTab for NetworkNode { } // Show loading spinner when stats are not available. + let server_stats = Node::get_stats(); if server_stats.is_none() || Node::is_restarting() || Node::is_stopping() { NetworkContent::loading_ui(ui, None); return; diff --git a/src/node/config.rs b/src/node/config.rs index fd5a6e7..1ece877 100644 --- a/src/node/config.rs +++ b/src/node/config.rs @@ -17,6 +17,8 @@ use std::io::{BufRead, BufReader, Write}; use std::net::{Ipv4Addr, SocketAddr, SocketAddrV4, TcpListener, ToSocketAddrs}; use std::path::PathBuf; use std::str::FromStr; +use local_ip_address::list_afinet_netifas; +use serde::{Deserialize, Serialize}; use grin_config::{config, ConfigError, ConfigMembers, GlobalConfig}; use grin_config::config::{API_SECRET_FILE_NAME, FOREIGN_API_SECRET_FILE_NAME, SERVER_CONFIG_FILE_NAME}; @@ -24,8 +26,7 @@ use grin_core::global::ChainTypes; use grin_p2p::{PeerAddr, Seeding}; use grin_p2p::msg::PeerAddrs; use grin_servers::common::types::ChainValidationMode; -use local_ip_address::list_afinet_netifas; -use serde::{Deserialize, Serialize}; +use rand::Rng; use crate::{AppConfig, Settings}; use crate::node::Node; @@ -68,7 +69,7 @@ impl PeersConfig { } /// Load saved peers to node server [`ConfigMembers`] config. - fn load_to_server_config() { + pub(crate) fn load_to_server_config() { let mut w_node_config = Settings::node_config_to_update(); // Load seeds. for seed in w_node_config.peers.seeds.clone() { @@ -111,7 +112,6 @@ impl PeersConfig { denied.peers.insert(denied.peers.len(), p); w_node_config.node.server.p2p_config.peers_deny = Some(denied); } - } // Load preferred peers. for peer in &w_node_config.peers.preferred.clone() { @@ -175,13 +175,35 @@ impl NodeConfig { fn save_default_node_server_config(chain_type: &ChainTypes) -> ConfigMembers { let sub_dir = Some(chain_type.shortname()); let path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, sub_dir.clone()); + let mut default_config = GlobalConfig::for_chain(chain_type); default_config.update_paths(&Settings::get_base_path(sub_dir)); - let config = default_config.members.unwrap(); + let mut config = default_config.members.unwrap(); + Self::setup_default_ports(&mut config); + Settings::write_to_file(&config, path); config } + /// Generate random p2p and api ports in ranges based on [`ChainTypes`]. + fn setup_default_ports(config: &mut ConfigMembers) { + let (api, p2p) = match config.server.chain_type { + ChainTypes::Mainnet => { + let api = rand::thread_rng().gen_range(30000..33000); + let p2p = rand::thread_rng().gen_range(33000..37000); + (api, p2p) + }, + _ => { + let api = rand::thread_rng().gen_range(40000..43000); + let p2p = rand::thread_rng().gen_range(43000..47000); + (api, p2p) + } + }; + let api_addr = config.server.api_http_addr.split_once(":").unwrap().0; + config.server.api_http_addr = format!("{}:{}", api_addr, api); + config.server.p2p_config.port = p2p; + } + /// Save default peers config for specified [`ChainTypes`]. fn save_default_peers_config(chain_type: &ChainTypes) -> PeersConfig { let sub_dir = Some(chain_type.shortname()); @@ -200,7 +222,6 @@ impl NodeConfig { /// Get server config to use for node server before start. pub fn node_server_config() -> ConfigMembers { - PeersConfig::load_to_server_config(); let r_config = Settings::node_config_to_read(); r_config.node.clone() } @@ -444,11 +465,7 @@ impl NodeConfig { 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 - }; + let same_running = NodeConfig::get_api_address() == format!("{}:{}", ip, port); if same_running || Self::is_host_port_available(ip, port) { return &Self::get_p2p_port() != port; } @@ -598,8 +615,6 @@ impl NodeConfig { w_node_config.save(); } - // P2P settings - /// Get P2P server port. pub fn get_p2p_port() -> String { Settings::node_config_to_read().node.server.p2p_config.port.to_string() @@ -613,11 +628,7 @@ impl NodeConfig { let (_, api_port) = Self::get_api_ip_port(); if Node::is_running() { // Check if P2P server with same port is running. - let same_running = if let Some(running_port) = Node::get_p2p_port() { - &running_port.to_string() == port - } else { - false - }; + let same_running = &NodeConfig::get_p2p_port() == port; if same_running || Self::is_port_available(port) { return &api_port != port; } diff --git a/src/node/mod.rs b/src/node/mod.rs index 81266f3..15d4ccf 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -19,4 +19,7 @@ mod node; pub use node::Node; mod config; -pub use config::*; \ No newline at end of file +pub use config::*; + +mod types; +pub use types::*; \ No newline at end of file diff --git a/src/node/node.rs b/src/node/node.rs index 568b83d..b327b21 100644 --- a/src/node/node.rs +++ b/src/node/node.rs @@ -14,18 +14,20 @@ use std::{fs, thread}; use std::path::PathBuf; -use std::sync::{Arc, RwLock, RwLockReadGuard}; +use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::time::Duration; - +use lazy_static::lazy_static; +use parking_lot::RwLock; use futures::channel::oneshot; + use grin_chain::SyncStatus; use grin_core::global; use grin_core::global::ChainTypes; use grin_servers::{Server, ServerStats, StratumServerConfig, StratumStats}; use grin_servers::common::types::Error; -use lazy_static::lazy_static; -use crate::node::NodeConfig; + +use crate::node::{NodeConfig, NodeError}; use crate::node::stratum::{StratumStopState, StratumServer}; lazy_static! { @@ -35,28 +37,27 @@ lazy_static! { /// Provides [`Server`] control, holds current status and statistics. pub struct Node { - /// Node [`Server`] statistics for UI. + /// Node [`Server`] statistics information. stats: Arc>>, - /// [`StratumServer`] statistics. + + /// [`StratumServer`] statistics information. stratum_stats: Arc>, + /// Flag to start [`StratumServer`]. + start_stratum_needed: AtomicBool, /// State to stop [`StratumServer`] from outside. stratum_stop_state: Arc, - /// Running API [`Server`] address. - api_addr: Arc>>, - /// Running P2P [`grin_p2p::Server`] port. - p2p_port: Arc>>, + /// Indicator if node [`Server`] is starting. starting: AtomicBool, - /// Thread flag to stop the [`Server`] and start it again. + /// Flag to stop the [`Server`] and start it again. restart_needed: AtomicBool, - /// Thread flag to stop the [`Server`]. + /// Flag to stop the [`Server`]. stop_needed: AtomicBool, /// Flag to check if app exit is needed after [`Server`] stop. exit_after_stop: AtomicBool, - /// Thread flag to start [`StratumServer`]. - start_stratum_needed: AtomicBool, - /// Error on [`Server`] start. - init_error: Option + + /// An error occurred on [`Server`] start. + error: Arc>> } impl Default for Node { @@ -65,14 +66,12 @@ impl Default for Node { stats: Arc::new(RwLock::new(None)), stratum_stats: Arc::new(grin_util::RwLock::new(StratumStats::default())), stratum_stop_state: Arc::new(StratumStopState::default()), - 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), exit_after_stop: AtomicBool::new(false), start_stratum_needed: AtomicBool::new(false), - init_error: None + error: Arc::new(RwLock::new(None)) } } } @@ -103,26 +102,6 @@ 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 [`grin_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 - } - } - /// Request to start [`StratumServer`]. pub fn start_stratum() { NODE_STATE.start_stratum_needed.store(true, Ordering::Relaxed); @@ -170,7 +149,7 @@ impl Node { /// Get node [`Server`] statistics. pub fn get_stats() -> Option { - NODE_STATE.stats.read().unwrap().clone() + NODE_STATE.stats.read().clone() } /// Check if [`Server`] is not syncing (disabled or just running after synchronization). @@ -201,6 +180,45 @@ impl Node { None } + /// Get [`Server`] error. + pub fn get_error() -> Option { + let r_err = NODE_STATE.error.read(); + if r_err.is_some() { + let e = r_err.as_ref().unwrap(); + // Setup a flag to show an error to clean up data. + let store_err = match e { + Error::Store(_) => true, + Error::Chain(_) => true, + _ => false + }; + if store_err { + return Some(NodeError::Storage); + } + + // Setup a flag to show P2P or API server error. + let p2p_api_err = match e { + Error::P2P(_) => Some(NodeError::P2P), + Error::API(_) => Some(NodeError::API), + _ => None + }; + if p2p_api_err.is_some() { + return p2p_api_err; + } + + // Setup a flag to show configuration error. + let config_err = match e { + Error::Configuration(_) => true, + _ => false + }; + return if config_err { + Some(NodeError::Configuration) + } else { + Some(NodeError::Unknown) + } + } + None + } + /// Start the [`Server`] at separate thread to update state with stats and handle statuses. fn start_server_thread() { thread::spawn(move || { @@ -226,7 +244,13 @@ impl Node { NODE_STATE.restart_needed.store(false, Ordering::Relaxed); } Err(e) => { - Self::on_start_error(&e); + // Setup an error. + { + let mut w_err = NODE_STATE.error.write(); + *w_err = Some(e); + } + // Reset server state. + Self::reset_server_state(true); break; } } @@ -234,8 +258,7 @@ impl Node { // Stop the server. server.stop(); // Clean stats and statuses. - Self::on_thread_stop(); - // Exit thread loop. + Self::reset_server_state(false); break; } @@ -256,7 +279,7 @@ impl Node { // Update server stats. if let Ok(stats) = server.get_server_stats() { { - let mut w_stats = NODE_STATE.stats.write().unwrap(); + let mut w_stats = NODE_STATE.stats.write(); *w_stats = Some(stats.clone()); } @@ -274,14 +297,20 @@ impl Node { } } Err(e) => { - Self::on_start_error(&e); + // Setup an error. + { + let mut w_err = NODE_STATE.error.write(); + *w_err = Some(e); + } + // Reset server state. + Self::reset_server_state(true); } } }); } - /// Reset stats and statuses on [`Server`] thread stop. - fn on_thread_stop() { + /// Clean up [`Server`] stats and statuses. + fn reset_server_state(has_error: bool) { NODE_STATE.starting.store(false, Ordering::Relaxed); NODE_STATE.restart_needed.store(false, Ordering::Relaxed); NODE_STATE.start_stratum_needed.store(false, Ordering::Relaxed); @@ -292,91 +321,40 @@ impl Node { let mut w_stratum_stats = NODE_STATE.stratum_stats.write(); *w_stratum_stats = StratumStats::default(); } - // Clean server stats. + // Reset server stats. { - let mut w_stats = NODE_STATE.stats.write().unwrap(); + let mut w_stats = NODE_STATE.stats.write(); *w_stats = None; } - // 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; + // Reset an error if needed. + if !has_error { + let mut w_err = NODE_STATE.error.write(); + *w_err = None; } } - /// Handle node [`Server`] error on start. - fn on_start_error(e: &Error) { - Self::on_thread_stop(); + /// Clean-up [`Server`] data if server is not running. + pub fn clean_up_data() { + if Self::is_running() { + return; + } + let config = NodeConfig::node_server_config(); + let server_config = config.server.clone(); - //TODO: Create error - // NODE_STATE.init_error = Some(e); + // Remove lock file if exists. + let mut lock_path = PathBuf::from(&server_config.db_root); + lock_path.push("grin.lock"); + if lock_path.exists() { + fs::remove_file(lock_path).unwrap(); + } - // // Clean-up server data on data init error. - // // TODO: Ask user to clean-up data - // let clean_server_and_recreate = || -> Server { - // let mut db_path = PathBuf::from(&server_config.db_root); - // db_path.push("grin.lock"); - // fs::remove_file(db_path).unwrap(); - // - // // Remove chain data on server start error - // let dirs_to_remove: Vec<&str> = vec!["header", "lmdb", "txhashset"]; - // for dir in dirs_to_remove { - // let mut path = PathBuf::from(&server_config.db_root); - // path.push(dir); - // fs::remove_dir_all(path).unwrap(); - // } - // - // // Recreate server - // let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) = - // Box::leak(Box::new(oneshot::channel::<()>())); - // server_result = Server::new(server_config.clone(), None, api_chan); - // server_result.unwrap() - // }; - - // Show err on server init error. - // TODO: Ask user to clean-up data - let show_error = |err: String| { - println!("Node server creation error:\n{}", err); - //TODO don't panic maybe - panic!("{}", err); - }; - - //TODO: Better error handling - match e { - Error::Store(e) => { - //TODO: Set err to ask user to clean data - panic!("{}", e); - //(clean_server_and_recreate)() - } - Error::Chain(e) => { - //TODO: Set err to ask user to clean data - panic!("{}", e); - //(clean_server_and_recreate)() - } - //TODO: Handle P2P error (Show config error msg) - Error::P2P(ref e) => { - (show_error)("P2P error".to_string()); - } - //TODO: Handle API error (Show config error msg) - Error::API(ref e) => { - (show_error)(e.to_string()); - } - //TODO: Seems like another node instance running? - Error::IOError(ref e) => { - (show_error)(e.to_string()); - } - //TODO: Show config error msg - Error::Configuration(ref e) => { - (show_error)(e.to_string()); - } - //TODO: Unknown error - _ => { - (show_error)("Unknown error".to_string()); + // Remove chain data. + let dirs_to_remove: Vec<&str> = vec!["header", "lmdb", "txhashset"]; + for dir in dirs_to_remove { + let mut path = PathBuf::from(&server_config.db_root); + path.push(dir); + if path.exists() { + fs::remove_dir_all(path).unwrap(); } } } @@ -564,26 +542,20 @@ fn start_node_server() -> Result { global::set_global_future_time_limit(future_time_limit); } - let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) = - Box::leak(Box::new(oneshot::channel::<()>())); - - // Set launching API server address from config to state. - { - let mut w_api_addr = NODE_STATE.api_addr.write().unwrap(); - *w_api_addr = Some(config.server.api_http_addr); - } - - // Set launching P2P server port from config to state. - { - let mut w_p2p_port = NODE_STATE.p2p_port.write().unwrap(); - *w_p2p_port = Some(config.server.p2p_config.port); - } - // Put flag to start stratum server if autorun is available. if NodeConfig::is_stratum_autorun_enabled() { NODE_STATE.start_stratum_needed.store(true, Ordering::Relaxed); } + // Reset an error. + { + let mut w_err = NODE_STATE.error.write(); + *w_err = None; + } + + // Start integrated node server. + let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) = + Box::leak(Box::new(oneshot::channel::<()>())); let server_result = Server::new(server_config, None, api_chan); // Delay after server start. diff --git a/src/node/types.rs b/src/node/types.rs new file mode 100644 index 0000000..31a731c --- /dev/null +++ b/src/node/types.rs @@ -0,0 +1,28 @@ +// Copyright 2024 The Grim Developers +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// Integrated node error type. +#[derive(Clone)] +pub enum NodeError { + /// Storage issue. + Storage, + /// P2P server issue. + P2P, + /// API server issue. + API, + /// Configuration issue. + Configuration, + /// Unknown error. + Unknown +} diff --git a/src/settings/config.rs b/src/settings/config.rs index a8958a7..e89210b 100644 --- a/src/settings/config.rs +++ b/src/settings/config.rs @@ -14,7 +14,8 @@ use grin_core::global::ChainTypes; use serde_derive::{Deserialize, Serialize}; -use crate::node::NodeConfig; + +use crate::node::{NodeConfig, PeersConfig}; use crate::Settings; use crate::wallet::ConnectionsConfig; @@ -95,10 +96,14 @@ impl AppConfig { w_node_config.node = node_config.node; w_node_config.peers = node_config.peers; } + // Load saved peers to node config. + { + PeersConfig::load_to_server_config(); + } // Load connections configuration { - let mut w_node_config = Settings::conn_config_to_update(); - *w_node_config = ConnectionsConfig::for_chain_type(chain_type); + let mut w_conn_config = Settings::conn_config_to_update(); + *w_conn_config = ConnectionsConfig::for_chain_type(chain_type); } } } diff --git a/src/settings/settings.rs b/src/settings/settings.rs index d63466e..6f354e3 100644 --- a/src/settings/settings.rs +++ b/src/settings/settings.rs @@ -15,13 +15,14 @@ use std::fs::{self, File}; use std::io::Write; use std::path::PathBuf; -use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; - -use grin_config::ConfigError; +use std::sync::Arc; use lazy_static::lazy_static; +use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard}; use serde::de::DeserializeOwned; use serde::Serialize; +use grin_config::ConfigError; + use crate::node::NodeConfig; use crate::settings::AppConfig; use crate::tor::TorConfig; @@ -81,42 +82,42 @@ impl Settings { /// Get node configuration to read values. pub fn node_config_to_read() -> RwLockReadGuard<'static, NodeConfig> { - SETTINGS_STATE.node_config.read().unwrap() + SETTINGS_STATE.node_config.read() } /// Get node configuration to update values. pub fn node_config_to_update() -> RwLockWriteGuard<'static, NodeConfig> { - SETTINGS_STATE.node_config.write().unwrap() + SETTINGS_STATE.node_config.write() } /// Get app configuration to read values. pub fn app_config_to_read() -> RwLockReadGuard<'static, AppConfig> { - SETTINGS_STATE.app_config.read().unwrap() + SETTINGS_STATE.app_config.read() } /// Get app configuration to update values. pub fn app_config_to_update() -> RwLockWriteGuard<'static, AppConfig> { - SETTINGS_STATE.app_config.write().unwrap() + SETTINGS_STATE.app_config.write() } /// Get connections configuration to read values. pub fn conn_config_to_read() -> RwLockReadGuard<'static, ConnectionsConfig> { - SETTINGS_STATE.conn_config.read().unwrap() + SETTINGS_STATE.conn_config.read() } /// Get connections configuration to update values. pub fn conn_config_to_update() -> RwLockWriteGuard<'static, ConnectionsConfig> { - SETTINGS_STATE.conn_config.write().unwrap() + SETTINGS_STATE.conn_config.write() } /// Get tor server configuration to read values. pub fn tor_config_to_read() -> RwLockReadGuard<'static, TorConfig> { - SETTINGS_STATE.tor_config.read().unwrap() + SETTINGS_STATE.tor_config.read() } /// Get tor server configuration to update values. pub fn tor_config_to_update() -> RwLockWriteGuard<'static, TorConfig> { - SETTINGS_STATE.tor_config.write().unwrap() + SETTINGS_STATE.tor_config.write() } /// Get base directory path for configuration.