config: optimize access to node config members, fix check for port availability

This commit is contained in:
ardocrat 2023-06-29 23:52:30 +03:00
parent 2f61a1a090
commit 719e28488f
9 changed files with 162 additions and 86 deletions

View file

@ -76,6 +76,7 @@ network_settings:
enter_value: Enter value enter_value: Enter value
port_unavailable: Specified port is unavailable port_unavailable: Specified port is unavailable
restart_app_required: App restart is required to apply changes. restart_app_required: App restart is required to apply changes.
restart_node_required: Node server restart is required to apply changes.
enable: Enable enable: Enable
disable: Disable disable: Disable
restart: Restart restart: Restart

View file

@ -76,6 +76,7 @@ network_settings:
enter_value: Введите значение enter_value: Введите значение
port_unavailable: Указанный порт недоступен port_unavailable: Указанный порт недоступен
restart_app_required: Для применения изменений требуется перезапуск приложения. restart_app_required: Для применения изменений требуется перезапуск приложения.
restart_node_required: Для применения изменений требуется перезапуск узла.
enable: Включить enable: Включить
disable: Выключить disable: Выключить
restart: Перезапустить restart: Перезапустить

View file

@ -337,15 +337,5 @@ impl Network {
ui.add_space(6.0); 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::<u16>() {
let ip_addr = Ipv4Addr::from_str(host.as_str()).unwrap();
let ipv4 = SocketAddrV4::new(ip_addr, p);
return TcpListener::bind(ipv4).is_ok();
}
false
}
} }

View file

@ -113,13 +113,9 @@ impl NetworkTab for NetworkMining {
}); });
columns[1].vertical_centered(|ui| { columns[1].vertical_centered(|ui| {
//TODO: Stratum mining wallet listening address. Replace with local wallet name. //TODO: Stratum mining wallet listening address. Replace with local wallet name.
let wallet_address = Settings::node_config_to_read() let wallet_addr = NodeConfig::get_stratum_wallet_addr().replace("http://", "");
.members.clone()
.server.stratum_mining_config.unwrap()
.wallet_listener_url
.replace("http://", "");
View::rounded_box(ui, View::rounded_box(ui,
wallet_address, wallet_addr,
t!("network_mining.rewards_wallet"), t!("network_mining.rewards_wallet"),
[false, true, false, true]); [false, true, false, true]);
}); });

View file

@ -44,7 +44,7 @@ pub struct NodeSetup {
impl Default for NodeSetup { impl Default for NodeSetup {
fn default() -> Self { fn default() -> Self {
let (api_ip, api_port) = NodeConfig::get_api_address_port(); 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 { Self {
api_port_edit: api_port, api_port_edit: api_port,
api_port_available_edit: is_api_port_available, api_port_available_edit: is_api_port_available,
@ -127,8 +127,13 @@ impl NodeSetup {
// Show API IP addresses to select. // Show API IP addresses to select.
let (api_ip, api_port) = NodeConfig::get_api_address_port(); let (api_ip, api_port) = NodeConfig::get_api_address_port();
Network::ip_list_ui(ui, &api_ip, &addrs, |selected_ip| { 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); NodeConfig::save_api_address_port(selected_ip, &api_port);
println!("12345 after save");
}); });
ui.label(RichText::new(t!("network_settings.api_port")) ui.label(RichText::new(t!("network_settings.api_port"))
@ -161,14 +166,21 @@ impl NodeSetup {
Navigator::show_modal(port_modal); Navigator::show_modal(port_modal);
cb.show_keyboard(); 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 { if !self.is_api_port_available {
// Show error when API server port is unavailable.
ui.label(RichText::new(t!("network_settings.port_unavailable")) ui.label(RichText::new(t!("network_settings.port_unavailable"))
.size(16.0) .size(16.0)
.color(Colors::RED)); .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, || { View::button(ui, t!("modal.save"), Colors::WHITE, || {
// Check if port is available. // Check if port is available.
let (ip, _) = NodeConfig::get_api_address_port(); 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; self.api_port_available_edit = available;
if self.api_port_available_edit { if self.api_port_available_edit {
@ -243,22 +258,3 @@ 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() && &current_ip == ip && &current_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
}

View file

@ -38,7 +38,7 @@ pub struct StratumServerSetup {
impl Default for StratumServerSetup { impl Default for StratumServerSetup {
fn default() -> Self { fn default() -> Self {
let (ip, port) = NodeConfig::get_stratum_address_port(); 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 { Self {
stratum_port_edit: port, stratum_port_edit: port,
stratum_port_available_edit: is_port_available, stratum_port_available_edit: is_port_available,
@ -72,11 +72,8 @@ impl StratumServerSetup {
// Show stratum IP addresses to select. // Show stratum IP addresses to select.
let (ip, port) = NodeConfig::get_stratum_address_port(); let (ip, port) = NodeConfig::get_stratum_address_port();
Network::ip_list_ui(ui, &ip, &all_ips, |selected_ip| { 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); 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")) ui.label(RichText::new(t!("network_settings.port"))
@ -169,7 +166,10 @@ impl StratumServerSetup {
View::button(ui, t!("modal.save"), Colors::WHITE, || { View::button(ui, t!("modal.save"), Colors::WHITE, || {
// Check if port is available. // Check if port is available.
let (ip, _) = NodeConfig::get_api_address_port(); 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; self.stratum_port_available_edit = available;
// Save port at config if it's available. // Save port at config if it's available.
@ -188,17 +188,3 @@ 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
}

View file

@ -70,7 +70,7 @@ impl View {
ui.input_mut().pointer = PointerState::default(); ui.input_mut().pointer = PointerState::default();
} }
if drag_resp.drag_released() || drag_resp.clicked() { if drag_resp.drag_released() || drag_resp.clicked() {
return true return true;
} }
false false
} }

View file

@ -14,7 +14,7 @@
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader, Write}; use std::io::{BufRead, BufReader, Write};
use std::net::IpAddr; use std::net::{IpAddr, Ipv4Addr, SocketAddrV4, TcpListener};
use std::str::FromStr; use std::str::FromStr;
use grin_config::{config, ConfigError, ConfigMembers, GlobalConfig}; use grin_config::{config, ConfigError, ConfigMembers, GlobalConfig};
@ -24,6 +24,7 @@ use grin_p2p::msg::PeerAddrs;
use grin_p2p::{PeerAddr, Seeding}; use grin_p2p::{PeerAddr, Seeding};
use grin_servers::common::types::ChainValidationMode; use grin_servers::common::types::ChainValidationMode;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::node::Node;
use crate::Settings; use crate::Settings;
@ -69,6 +70,12 @@ impl NodeConfig {
Settings::write_to_file(&self.members, config_path); 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. /// Check that the api secret files exist and are valid.
fn check_api_secret_files( fn check_api_secret_files(
chain_type: &ChainTypes, 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::<u16>() {
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. /// Get stratum server IP address and port.
pub fn get_stratum_address_port() -> (String, String) { pub fn get_stratum_address_port() -> (String, String) {
let r_config = Settings::node_config_to_read(); let r_config = Settings::node_config_to_read();
@ -114,6 +131,27 @@ impl NodeConfig {
w_node_config.save(); 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. /// Check if stratum mining server autorun is enabled.
pub fn is_stratum_autorun_enabled() -> bool { pub fn is_stratum_autorun_enabled() -> bool {
let stratum_config = Settings::node_config_to_read() let stratum_config = Settings::node_config_to_read()
@ -141,18 +179,6 @@ impl NodeConfig {
w_node_config.save(); 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. /// Get API server IP address and port.
pub fn get_api_address_port() -> (String, String) { pub fn get_api_address_port() -> (String, String) {
let r_config = Settings::node_config_to_read(); let r_config = Settings::node_config_to_read();
@ -173,6 +199,25 @@ impl NodeConfig {
w_node_config.save(); 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. /// Get API secret text.
pub fn get_api_secret() -> String { pub fn get_api_secret() -> String {
let r_config = Settings::node_config_to_read(); let r_config = Settings::node_config_to_read();

View file

@ -26,6 +26,7 @@ use grin_servers::{Server, ServerStats};
use grin_servers::common::types::Error; use grin_servers::common::types::Error;
use jni::sys::{jboolean, jstring}; use jni::sys::{jboolean, jstring};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use crate::node::NodeConfig;
use crate::Settings; use crate::Settings;
@ -38,6 +39,10 @@ lazy_static! {
pub struct Node { pub struct Node {
/// Statistics data for UI. /// Statistics data for UI.
stats: Arc<RwLock<Option<ServerStats>>>, stats: Arc<RwLock<Option<ServerStats>>>,
/// Running API server address.
api_addr: Arc<RwLock<Option<String>>>,
/// Running P2P server port.
p2p_port: Arc<RwLock<Option<u16>>>,
/// Indicator if server is starting. /// Indicator if server is starting.
starting: AtomicBool, starting: AtomicBool,
/// Thread flag to stop the server and start it again. /// Thread flag to stop the server and start it again.
@ -56,6 +61,8 @@ impl Default for Node {
fn default() -> Self { fn default() -> Self {
Self { Self {
stats: Arc::new(RwLock::new(None)), stats: Arc::new(RwLock::new(None)),
api_addr: Arc::new(RwLock::new(None)),
p2p_port: Arc::new(RwLock::new(None)),
starting: AtomicBool::new(false), starting: AtomicBool::new(false),
restart_needed: AtomicBool::new(false), restart_needed: AtomicBool::new(false),
stop_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<String> {
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<u16> {
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. /// Start stratum server.
pub fn start_stratum_server() { pub fn start_stratum_server() {
NODE_STATE.start_stratum_server.store(true, Ordering::Relaxed); NODE_STATE.start_stratum_server.store(true, Ordering::Relaxed);
@ -165,8 +192,9 @@ impl Node {
NODE_STATE.restart_needed.store(false, Ordering::Relaxed); NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
} }
Err(e) => { Err(e) => {
Self::handle_init_error(&e); NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
return; Self::on_start_error(&e);
break;
} }
} }
} else if Self::is_stopping() { } else if Self::is_stopping() {
@ -182,10 +210,21 @@ impl Node {
NODE_STATE.starting.store(false, Ordering::Relaxed); NODE_STATE.starting.store(false, Ordering::Relaxed);
NODE_STATE.stop_needed.store(false, Ordering::Relaxed); NODE_STATE.stop_needed.store(false, Ordering::Relaxed);
NODE_STATE.start_stratum_server.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; break;
} else { } else {
// Start stratum mining server.
if Self::is_stratum_server_starting() { if Self::is_stratum_server_starting() {
// Start mining server.
let stratum_config = server let stratum_config = server
.config .config
.stratum_mining_config .stratum_mining_config
@ -195,16 +234,14 @@ impl Node {
// Wait for mining server to start and update status. // Wait for mining server to start and update status.
thread::sleep(Duration::from_millis(100)); thread::sleep(Duration::from_millis(100));
NODE_STATE.start_stratum_server.store(false, Ordering::Relaxed); 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(); 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 { if first_start {
@ -217,14 +254,25 @@ impl Node {
} }
} }
Err(e) => { 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. /// 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 //TODO: Create error
// NODE_STATE.init_error = Some(e); // NODE_STATE.init_error = Some(e);
@ -412,7 +460,7 @@ impl Node {
/// Start the [`Server`] for node. /// Start the [`Server`] for node.
fn start_server() -> Result<Server, Error> { fn start_server() -> Result<Server, Error> {
// Get current global config // Get current global config
let config = &Settings::node_config_to_read().members; let config = NodeConfig::get_members();
let server_config = config.server.clone(); let server_config = config.server.clone();
// Remove temporary file dir // Remove temporary file dir
@ -458,6 +506,19 @@ fn start_server() -> Result<Server, Error> {
let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) = let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) =
Box::leak(Box::new(oneshot::channel::<()>())); 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); let server_result = Server::new(server_config.clone(), None, api_chan);
server_result server_result
} }