From 1a74678c67861970407b17b2bba911acbb86b63d Mon Sep 17 00:00:00 2001 From: ardocrat Date: Thu, 29 Jun 2023 03:42:03 +0300 Subject: [PATCH] ui + config: optimize ip list at config ui, api port modal, update, translations, better check ports availability, refactor settings initialization and arguments passing --- locales/en.yml | 21 +-- locales/ru.yml | 23 ++-- src/gui/screens/root.rs | 2 +- src/gui/views/modal.rs | 5 +- src/gui/views/network.rs | 72 ++++++++-- src/gui/views/network_mining.rs | 24 ++-- src/gui/views/network_settings.rs | 7 +- src/gui/views/settings_node.rs | 221 ++++++++++++++++++++---------- src/gui/views/settings_stratum.rs | 168 +++++++++-------------- src/node/config.rs | 69 ++++++++-- src/settings.rs | 17 +-- 11 files changed, 381 insertions(+), 248 deletions(-) diff --git a/locales/en.yml b/locales/en.yml index b99a3dc..5862040 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -11,7 +11,7 @@ network: restart: Restart autorun: Autorun disabled_server: 'Enable integrated node or add another connection method by pressing %{dots} in the top-left corner of the screen.' - no_ip_addresses: There are no available IP addresses on your system, server cannot be started, check your network connectivity. + no_ips: There are no available IP addresses on your system, server cannot be started, check your network connectivity. sync_status: node_restarting: Node is restarting node_down: Node is down @@ -60,7 +60,6 @@ network_mining: enable_server: Enable server server_setting: 'Enable stratum server or change more settings by selecting %{settings} at the bottom of the screen. App restart is required to change settings of the running server.' info: 'Mining server is enabled, you can change its settings by selecting %{settings} at the bottom of the screen. Data is updating when devices are connected.' - port_unavailable: Specified port is unavailable rewards_wallet: Wallet for rewards server: Stratum server address: Address @@ -72,15 +71,17 @@ network_mining: disconnected: Disconnected network_settings: port: Port - ip_address: IP Address + ip: IP Address change_port: Change port - enter_value: 'Enter value:' - server: - title: Server - enable: Enable - disable: Disable - restart: Restart - api_ip_address: API IP Address + enter_value: Enter value + port_unavailable: Specified port is unavailable + restart_app_required: App restart is required to apply changes. + enable: Enable + disable: Disable + restart: Restart + server: Server + api_ip: API IP Address + api_port: API Port modal: cancel: Cancel save: Save diff --git a/locales/ru.yml b/locales/ru.yml index 4660588..e902d1c 100644 --- a/locales/ru.yml +++ b/locales/ru.yml @@ -11,7 +11,7 @@ network: restart: Перезапустить autorun: Автозапуск disabled_server: 'Включите встроенный узел или добавьте другой способ подключения, нажав %{dots} в левом-верхнем углу экрана.' - no_ip_addresses: В вашей системе отсутствуют доступные IP адреса, запуск сервера невозможен, проверьте ваше подключение к сети. + no_ips: В вашей системе отсутствуют доступные IP адреса, запуск сервера невозможен, проверьте ваше подключение к сети. sync_status: node_restarting: Узел перезапускается node_down: Узел выключен @@ -60,7 +60,6 @@ network_mining: enable_server: Включить сервер server_setting: 'Включите stratum-сервер или измените больше настроек, выбрав %{settings} внизу экрана. Для изменения настроек запущенного сервера потребуется перезапуск приложения.' info: 'Сервер майнинга запущен, вы можете изменить его настройки, выбрав %{settings} внизу экрана. Данные обновляются, когда устройства подключены.' - port_unavailable: Указанный порт недоступен rewards_wallet: Кошелёк для наград server: Stratum-сервер address: Адрес @@ -71,20 +70,22 @@ network_mining: connected: Подключен disconnected: Отключен network_settings: - ip_address: IP Адрес + ip: IP Адрес port: Порт change_port: Изменить порт - enter_value: 'Введите значение:' - server: - title: Сервер - enable: Включить - disable: Выключить - restart: Перезапустить - api_ip_address: API IP Адрес + enter_value: Введите значение + port_unavailable: Указанный порт недоступен + restart_app_required: Для применения изменений требуется перезапуск приложения. + enable: Включить + disable: Выключить + restart: Перезапустить + server: Сервер + api_ip: API IP Адрес + api_port: API Порт modal: cancel: Отмена save: Сохранить confirmation: Подтверждение modal_exit: description: Вы уверены, что хотите выйти из приложения? - exit: Выход + exit: Выход \ No newline at end of file diff --git a/src/gui/screens/root.rs b/src/gui/screens/root.rs index 8f82e15..5a4d045 100644 --- a/src/gui/screens/root.rs +++ b/src/gui/screens/root.rs @@ -45,7 +45,7 @@ impl Default for Root { } impl ModalContainer for Root { - fn allowed_modal_ids(&self) -> &Vec<&'static str> { + fn modal_ids(&self) -> &Vec<&'static str> { self.allowed_modal_ids.as_ref() } } diff --git a/src/gui/views/modal.rs b/src/gui/views/modal.rs index f312017..b6ebb5f 100644 --- a/src/gui/views/modal.rs +++ b/src/gui/views/modal.rs @@ -23,11 +23,12 @@ use crate::gui::views::View; /// Contains modal ids to draw at current container if possible. pub trait ModalContainer { - fn allowed_modal_ids(&self) -> &Vec<&'static str>; + /// List of modal ids to show at current view container. + fn modal_ids(&self) -> &Vec<&'static str>; /// Check if it's possible to show modal. fn can_show_modal(&self, id: &'static str) -> bool { - self.allowed_modal_ids().contains(&id) + self.modal_ids().contains(&id) } } diff --git a/src/gui/views/network.rs b/src/gui/views/network.rs index 17643a2..a8b9329 100644 --- a/src/gui/views/network.rs +++ b/src/gui/views/network.rs @@ -29,6 +29,7 @@ use crate::gui::views::network_metrics::NetworkMetrics; use crate::gui::views::network_mining::NetworkMining; use crate::gui::views::network_node::NetworkNode; use crate::gui::views::network_settings::NetworkSettings; +use crate::gui::views::settings_node::NodeSetup; use crate::gui::views::settings_stratum::StratumServerSetup; use crate::node::Node; use crate::Settings; @@ -60,23 +61,24 @@ impl NetworkTabType { pub struct Network { current_tab: Box, - allowed_modal_ids: Vec<&'static str>, + modal_ids: Vec<&'static str>, } impl Default for Network { fn default() -> Self { Self { current_tab: Box::new(NetworkNode::default()), - allowed_modal_ids: vec![ - StratumServerSetup::STRATUM_PORT_MODAL + modal_ids: vec![ + StratumServerSetup::STRATUM_PORT_MODAL, + NodeSetup::API_PORT_MODAL ] } } } impl ModalContainer for Network { - fn allowed_modal_ids(&self) -> &Vec<&'static str> { - self.allowed_modal_ids.as_ref() + fn modal_ids(&self) -> &Vec<&'static str> { + self.modal_ids.as_ref() } } @@ -278,10 +280,57 @@ impl Network { addresses } + /// Draw IP list radio buttons. + pub fn ip_list_ui(ui: &mut egui::Ui, + saved_ip: &String, + ips: &Vec, + on_change: impl FnOnce(&String)) { + let saved_ip_addr = &IpAddr::from_str(saved_ip.as_str()).unwrap(); + let mut selected_ip_addr = saved_ip_addr; + + // Set first IP address as current if saved is not present at system. + if !ips.contains(selected_ip_addr) { + selected_ip_addr = ips.get(0).unwrap(); + } + + // Show available IP addresses on the system. + let _ = ips.chunks(2).map(|x| { + if x.len() == 2 { + ui.columns(2, |columns| { + let ip_addr_l = x.get(0).unwrap(); + columns[0].vertical_centered(|ui| { + View::radio_value(ui, + &mut selected_ip_addr, + ip_addr_l, + ip_addr_l.to_string()); + }); + let ip_addr_r = x.get(1).unwrap(); + columns[1].vertical_centered(|ui| { + View::radio_value(ui, + &mut selected_ip_addr, + ip_addr_r, + ip_addr_r.to_string()); + }) + }); + } else { + let ip_addr = x.get(0).unwrap(); + View::radio_value(ui, + &mut selected_ip_addr, + ip_addr, + ip_addr.to_string()); + } + ui.add_space(12.0); + }).collect::>(); + + if saved_ip_addr != selected_ip_addr { + (on_change)(&selected_ip_addr.to_string()); + } + } + /// Show message when IP addresses are not available at system. pub fn no_ip_address_ui(ui: &mut egui::Ui) { ui.vertical_centered(|ui| { - ui.label(RichText::new(t!("network.no_ip_addresses")) + ui.label(RichText::new(t!("network.no_ips")) .size(16.0) .color(Colors::INACTIVE_TEXT) ); @@ -290,10 +339,13 @@ impl Network { } /// Check whether a port is available on the provided host. - pub fn is_port_available(host: &str, port: u16) -> bool { - let ip_addr = Ipv4Addr::from_str(host).unwrap(); - let ipv4 = SocketAddrV4::new(ip_addr, port); - TcpListener::bind(ipv4).is_ok() + 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 b46e148..45f7ad6 100644 --- a/src/gui/views/network_mining.rs +++ b/src/gui/views/network_mining.rs @@ -77,29 +77,21 @@ impl NetworkTab for NetworkMining { ui.add_space(4.0); // Show button to enable stratum server if port is available. - if self.stratum_server_setup.is_stratum_port_available { + if self.stratum_server_setup.is_port_available { ui.add_space(6.0); View::button(ui, t!("network_mining.enable_server"), Colors::GOLD, || { Node::start_stratum_server(); }); ui.add_space(2.0); + + // Show stratum server autorun checkbox. + let stratum_enabled = NodeConfig::is_stratum_autorun_enabled(); + View::checkbox(ui, stratum_enabled, t!("network.autorun"), || { + NodeConfig::toggle_stratum_autorun(); + }); + ui.add_space(6.0); } - - let stratum_enabled = Settings::node_config_to_read() - .members.clone() - .server.stratum_mining_config.unwrap() - .enable_stratum_server.unwrap(); - - // Show stratum server autorun checkbox. - View::checkbox(ui, stratum_enabled, t!("network.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(!stratum_enabled); - w_node_config.save(); - }); }); - ui.add_space(6.0); }); return; } else if Node::is_stratum_server_starting() { diff --git a/src/gui/views/network_settings.rs b/src/gui/views/network_settings.rs index 99deadf..14c9dc7 100644 --- a/src/gui/views/network_settings.rs +++ b/src/gui/views/network_settings.rs @@ -37,6 +37,11 @@ impl NetworkTab for NetworkSettings { } fn on_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) { - + match modal.id { + NodeSetup::API_PORT_MODAL => { + self.node_setup.api_port_modal_ui(ui, modal, cb); + }, + _ => {} + } } } \ No newline at end of file diff --git a/src/gui/views/settings_node.rs b/src/gui/views/settings_node.rs index 385e683..470ed0b 100644 --- a/src/gui/views/settings_node.rs +++ b/src/gui/views/settings_node.rs @@ -14,24 +14,22 @@ use std::net::IpAddr; use std::str::FromStr; -use egui::RichText; -use crate::gui::Colors; -use crate::gui::icons::COMPUTER_TOWER; +use egui::{RichText, TextStyle, Widget}; +use crate::gui::{Colors, Navigator}; +use crate::gui::icons::{COMPUTER_TOWER, POWER}; use crate::gui::platform::PlatformCallbacks; -use crate::gui::views::{Network, View}; +use crate::gui::views::{Modal, ModalPosition, Network, View}; use crate::node::{Node, NodeConfig}; /// Integrated node server setup ui section. pub struct NodeSetup { - /// API IP address to be used inside edit modal. - api_address_edit: String, /// API port to be used inside edit modal. api_port_edit: String, /// Flag to check if API port is available inside edit modal. api_port_available_edit: bool, /// Flag to check if API port is available from saved config value. - pub(crate) api_port_available: bool, + pub(crate) is_api_port_available: bool, /// API secret to be used inside edit modal. api_secret_edit: String, @@ -45,13 +43,12 @@ pub struct NodeSetup { impl Default for NodeSetup { fn default() -> Self { - let (api_address, api_port) = NodeConfig::get_api_address_port(); - let is_api_port_available = Network::is_port_available(api_address.as_str(), api_port); + let (api_ip, api_port) = NodeConfig::get_api_address_port(); + let is_api_port_available = is_api_port_available(&api_ip, &api_port); Self { - api_address_edit: api_address, - api_port_edit: api_port.to_string(), + api_port_edit: api_port, api_port_available_edit: is_api_port_available, - api_port_available: is_api_port_available, + is_api_port_available, api_secret_edit: "".to_string(), foreign_api_secret_edit: "".to_string(), ftl_edit: "".to_string(), @@ -62,10 +59,10 @@ impl Default for NodeSetup { const SECRET_SYMBOLS: &'static str = "••••••••••••"; impl NodeSetup { - pub const API_PORT_MODAL: &'static str = "stratum_port"; + pub const API_PORT_MODAL: &'static str = "api_port"; pub fn ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { - View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network_settings.server.title"))); + View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network_settings.server"))); View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(4.0); @@ -79,17 +76,17 @@ impl NodeSetup { if Node::is_running() { ui.scope(|ui| { // Setup spacing between buttons. - ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); + ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); ui.add_space(6.0); ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { - View::button(ui, t!("network_settings.server.disable"), Colors::GOLD, || { + View::button(ui, t!("network_settings.disable"), Colors::GOLD, || { Node::stop(false); }); }); columns[1].vertical_centered_justified(|ui| { - View::button(ui, t!("network_settings.server.restart"), Colors::GOLD, || { + View::button(ui, t!("network_settings.restart"), Colors::GOLD, || { Node::restart(); }); }); @@ -98,7 +95,8 @@ impl NodeSetup { } else { ui.add_space(6.0); ui.vertical_centered(|ui| { - View::button(ui, t!("network_settings.server.enable"), Colors::GOLD, || { + let enable_text = format!("{} {}", POWER, t!("network_settings.enable")); + View::button(ui, enable_text, Colors::GOLD, || { Node::start(); }); }); @@ -112,7 +110,7 @@ impl NodeSetup { ui.add_space(4.0); let addrs = Network::get_ip_list(); - // Show error message when IP addresses are not available on the system. + // Show message when IP addresses are not available on the system. if addrs.is_empty() { Network::no_ip_address_ui(ui); ui.add_space(4.0); @@ -121,63 +119,146 @@ impl NodeSetup { ui.add_space(4.0); ui.vertical_centered(|ui| { - ui.label(RichText::new(t!("network_settings.server.api_ip_address")) + ui.label(RichText::new(t!("network_settings.api_ip")) .size(16.0) .color(Colors::GRAY) ); ui.add_space(6.0); - }); - - // Show API IP address setup. - self.api_ip_address_setup_ui(ui, addrs) - } - } - - /// Show API IP address setup. - fn api_ip_address_setup_ui(&mut self, ui: &mut egui::Ui, addrs: Vec) { - let (addr, port) = NodeConfig::get_api_address_port(); - let saved_ip_addr = &IpAddr::from_str(addr.as_str()).unwrap(); - let mut selected_addr = saved_ip_addr; - - // Set first IP address as current if saved is not present at system. - if !addrs.contains(selected_addr) { - selected_addr = addrs.get(0).unwrap(); - } - - // Show available IP addresses on the system. - let _ = addrs.chunks(2).map(|x| { - if x.len() == 2 { - ui.columns(2, |columns| { - let addr0 = x.get(0).unwrap(); - columns[0].vertical_centered(|ui| { - View::radio_value(ui, - &mut selected_addr, - addr0, - addr0.to_string()); - }); - let addr1 = x.get(1).unwrap(); - columns[1].vertical_centered(|ui| { - View::radio_value(ui, - &mut selected_addr, - addr1, - addr1.to_string()); - }) + // 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); + NodeConfig::save_api_address_port(selected_ip, &api_port); }); - } else { - let addr = x.get(0).unwrap(); - View::radio_value(ui, - &mut selected_addr, - addr, - addr.to_string()); - } - ui.add_space(10.0); - }).collect::>(); - // Save stratum server address at config if it was changed and check port availability. - if saved_ip_addr != selected_addr { - NodeConfig::save_api_server_address_port(selected_addr.to_string(), port.to_string()); - let available = Network::is_port_available(selected_addr.to_string().as_str(), port); - self.api_port_available = available; + ui.label(RichText::new(t!("network_settings.api_port")) + .size(16.0) + .color(Colors::GRAY) + ); + ui.add_space(6.0); + // Show API port setup. + self.api_port_setup_ui(ui, cb); + + View::horizontal_line(ui, Colors::ITEM_STROKE); + ui.add_space(6.0); + }); } } + + /// Draw API port setup ui. + fn api_port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + let (_, port) = NodeConfig::get_api_address_port(); + // Show button to choose API server port. + View::button(ui, port.clone(), Colors::BUTTON, || { + // Setup values for modal. + self.api_port_edit = port; + self.api_port_available_edit = self.is_api_port_available; + + // Show API port modal. + let port_modal = Modal::new(Self::API_PORT_MODAL) + .position(ModalPosition::CenterTop) + .title(t!("network_settings.change_port")); + Navigator::show_modal(port_modal); + cb.show_keyboard(); + }); + ui.add_space(14.0); + + // Show error when API server port is unavailable. + if !self.is_api_port_available { + ui.label(RichText::new(t!("network_settings.port_unavailable")) + .size(16.0) + .color(Colors::RED)); + ui.add_space(12.0); + } + } + + /// Draw API port [`Modal`] content ui. + pub fn api_port_modal_ui(&mut self, + ui: &mut egui::Ui, + modal: &Modal, + cb: &dyn PlatformCallbacks) { + ui.add_space(6.0); + ui.vertical_centered(|ui| { + ui.label(RichText::new(t!("network_settings.enter_value")) + .size(16.0) + .color(Colors::GRAY)); + ui.add_space(8.0); + + // Draw API port text edit. + let text_edit_resp = egui::TextEdit::singleline(&mut self.api_port_edit) + .font(TextStyle::Heading) + .desired_width(58.0) + .cursor_at_end(true) + .ui(ui); + text_edit_resp.request_focus(); + if text_edit_resp.clicked() { + cb.show_keyboard(); + } + + // Show error when specified port is unavailable. + if !self.api_port_available_edit { + ui.add_space(12.0); + ui.label(RichText::new(t!("network_settings.port_unavailable")) + .size(16.0) + .color(Colors::RED)); + } + + ui.add_space(12.0); + + // Show modal buttons. + ui.scope(|ui| { + // Setup spacing between buttons. + ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); + + ui.columns(2, |columns| { + columns[0].vertical_centered_justified(|ui| { + View::button(ui, t!("modal.cancel"), Colors::WHITE, || { + cb.hide_keyboard(); + modal.close(); + }); + }); + columns[1].vertical_centered_justified(|ui| { + 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); + self.api_port_available_edit = available; + + if self.api_port_available_edit { + // Save port at config if it's available. + NodeConfig::save_api_address_port( + &ip, + &self.api_port_edit + ); + + self.is_api_port_available = true; + cb.hide_keyboard(); + modal.close(); + } + }); + }); + }); + ui.add_space(6.0); + }); + }); + } +} + +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 a0a375c..f944b39 100644 --- a/src/gui/views/settings_stratum.rs +++ b/src/gui/views/settings_stratum.rs @@ -22,29 +22,27 @@ use crate::gui::icons::WRENCH; use crate::gui::platform::PlatformCallbacks; use crate::gui::views::{Modal, ModalPosition, Network, View}; use crate::node::NodeConfig; +use crate::Settings; /// Stratum server setup ui section. pub struct StratumServerSetup { - /// Stratum IP address to be used inside edit modal. - stratum_address_edit: String, /// Stratum port to be used inside edit modal. stratum_port_edit: String, /// Flag to check if stratum port is available inside edit modal. stratum_port_available_edit: bool, /// Flag to check if stratum port is available from saved config value. - pub(crate) is_stratum_port_available: bool + pub(crate) is_port_available: bool } impl Default for StratumServerSetup { fn default() -> Self { - let (stratum_address, stratum_port) = NodeConfig::get_stratum_address_port(); - let is_port_available = Network::is_port_available(stratum_address.as_str(), stratum_port); + let (ip, port) = NodeConfig::get_stratum_address_port(); + let is_port_available = is_stratum_port_available(&ip, &port); Self { - stratum_address_edit: stratum_address, - stratum_port_edit: stratum_port.to_string(), + stratum_port_edit: port, stratum_port_available_edit: is_port_available, - is_stratum_port_available: is_port_available + is_port_available } } } @@ -58,66 +56,70 @@ impl StratumServerSetup { View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(4.0); - // Show error message when IP addresses are not available on the system. - let addrs = Network::get_ip_list(); - if addrs.is_empty() { + // Show message when IP addresses are not available on the system. + let all_ips = Network::get_ip_list(); + if all_ips.is_empty() { Network::no_ip_address_ui(ui); return; } ui.vertical_centered(|ui| { - ui.label(RichText::new(t!("network_settings.ip_address")) + ui.label(RichText::new(t!("network_settings.ip")) .size(16.0) .color(Colors::GRAY) ); ui.add_space(6.0); - - // Show stratum IP address setup. - self.ip_address_setup_ui(ui, addrs); - - View::horizontal_line(ui, Colors::ITEM_STROKE); - ui.add_space(6.0); + // 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); + 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")) .size(16.0) .color(Colors::GRAY) ); - - // Show button to choose stratum server port. ui.add_space(6.0); - let (stratum_address, stratum_port) = NodeConfig::get_stratum_address_port(); - View::button(ui, stratum_port.to_string(), Colors::BUTTON, || { - // Setup values for modal. - self.stratum_address_edit = stratum_address.clone(); - self.stratum_port_edit = stratum_port.to_string(); - self.stratum_port_available_edit = Network::is_port_available( - stratum_address.as_str(), - stratum_port - ); - - // Show stratum port modal. - let port_modal = Modal::new(Self::STRATUM_PORT_MODAL) - .position(ModalPosition::CenterTop) - .title(t!("network_settings.change_port")); - Navigator::show_modal(port_modal); - cb.show_keyboard(); - }); - ui.add_space(14.0); - - // Show error when stratum server port is unavailable. - if !self.is_stratum_port_available { - ui.label(RichText::new(t!("network_mining.port_unavailable")) - .size(16.0) - .color(Colors::RED)); - ui.add_space(12.0); - } + // Show stratum port setup. + self.port_setup_ui(ui, cb); View::horizontal_line(ui, Colors::ITEM_STROKE); ui.add_space(6.0); }); } - /// Draw stratum port [`Modal`] content. + /// Draw stratum port setup ui. + fn port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) { + let (_, port) = NodeConfig::get_stratum_address_port(); + // Show button to choose stratum server port. + View::button(ui, port.clone(), Colors::BUTTON, || { + // Setup values for modal. + self.stratum_port_edit = port; + self.stratum_port_available_edit = self.is_port_available; + + // Show stratum port modal. + let port_modal = Modal::new(Self::STRATUM_PORT_MODAL) + .position(ModalPosition::CenterTop) + .title(t!("network_settings.change_port")); + Navigator::show_modal(port_modal); + cb.show_keyboard(); + }); + ui.add_space(14.0); + + // Show error when stratum server port is unavailable. + if !self.is_port_available { + ui.label(RichText::new(t!("network_settings.port_unavailable")) + .size(16.0) + .color(Colors::RED)); + ui.add_space(12.0); + } + } + + /// Draw stratum port [`Modal`] content ui. pub fn stratum_port_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, @@ -143,7 +145,7 @@ impl StratumServerSetup { // Show error when specified port is unavailable. if !self.stratum_port_available_edit { ui.add_space(12.0); - ui.label(RichText::new(t!("network_mining.port_unavailable")) + ui.label(RichText::new(t!("network_settings.port_unavailable")) .size(16.0) .color(Colors::RED)); } @@ -153,7 +155,7 @@ impl StratumServerSetup { // Show modal buttons. ui.scope(|ui| { // Setup spacing between buttons. - ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0); + ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0); ui.columns(2, |columns| { columns[0].vertical_centered_justified(|ui| { @@ -166,21 +168,15 @@ impl StratumServerSetup { columns[1].vertical_centered_justified(|ui| { View::button(ui, t!("modal.save"), Colors::WHITE, || { // Check if port is available. - let port_parse = self.stratum_port_edit.parse::(); - let is_available = port_parse.is_ok() && Network::is_port_available( - self.stratum_address_edit.as_str(), - port_parse.unwrap() - ); - self.stratum_port_available_edit = is_available; + let (ip, _) = NodeConfig::get_api_address_port(); + let available = is_stratum_port_available(&ip, &self.stratum_port_edit); + self.stratum_port_available_edit = available; // Save port at config if it's available. if self.stratum_port_available_edit { - NodeConfig::save_stratum_address_port( - self.stratum_address_edit.clone(), - self.stratum_port_edit.clone() - ); + NodeConfig::save_stratum_address_port(&ip, &self.stratum_port_edit); - self.is_stratum_port_available = true; + self.is_port_available = true; cb.hide_keyboard(); modal.close(); } @@ -191,52 +187,18 @@ impl StratumServerSetup { }); }); } +} - /// Show stratum IP address setup. - fn ip_address_setup_ui(&mut self, ui: &mut egui::Ui, addrs: Vec) { - let (addr, port) = NodeConfig::get_stratum_address_port(); - let saved_ip_addr = &IpAddr::from_str(addr.as_str()).unwrap(); - let mut selected_addr = saved_ip_addr; - - // Set first IP address as current if saved is not present at system. - if !addrs.contains(selected_addr) { - selected_addr = addrs.get(0).unwrap(); - } - - // Show available IP addresses on the system. - let _ = addrs.chunks(2).map(|x| { - if x.len() == 2 { - ui.columns(2, |columns| { - let addr0 = x.get(0).unwrap(); - columns[0].vertical_centered(|ui| { - View::radio_value(ui, - &mut selected_addr, - addr0, - addr0.to_string()); - }); - let addr1 = x.get(1).unwrap(); - columns[1].vertical_centered(|ui| { - View::radio_value(ui, - &mut selected_addr, - addr1, - addr1.to_string()); - }) - }); +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 { - let addr = x.get(0).unwrap(); - View::radio_value(ui, - &mut selected_addr, - addr, - addr.to_string()); + true } - ui.add_space(10.0); - }).collect::>(); - - // Save stratum server address at config if it was changed and check port availability. - if saved_ip_addr != selected_addr { - NodeConfig::save_stratum_address_port(selected_addr.to_string(), port.to_string()); - let available = Network::is_port_available(selected_addr.to_string().as_str(), port); - self.is_stratum_port_available = available; } } + false } \ No newline at end of file diff --git a/src/node/config.rs b/src/node/config.rs index cf03870..a8d1844 100644 --- a/src/node/config.rs +++ b/src/node/config.rs @@ -35,7 +35,7 @@ pub struct NodeConfig { impl NodeConfig { /// Initialize integrated node config. - pub fn init(chain_type: ChainTypes) -> Self { + pub fn init(chain_type: &ChainTypes) -> Self { let _ = Self::check_api_secret_files(chain_type, API_SECRET_FILE_NAME); let _ = Self::check_api_secret_files(chain_type, FOREIGN_API_SECRET_FILE_NAME); @@ -46,11 +46,11 @@ impl NodeConfig { } /// Initialize config with provided [`ChainTypes`]. - pub fn for_chain_type(chain_type: ChainTypes) -> ConfigMembers { + pub fn for_chain_type(chain_type: &ChainTypes) -> ConfigMembers { let path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type)); let parsed = Settings::read_from_file::(path.clone()); if !path.exists() || parsed.is_err() { - let mut default_config = GlobalConfig::for_chain(&chain_type); + let mut default_config = GlobalConfig::for_chain(chain_type); default_config.update_paths(&Settings::get_working_path(Some(chain_type))); let config = default_config.members.unwrap(); Settings::write_to_file(&config, path); @@ -62,14 +62,16 @@ impl NodeConfig { /// Save node config to disk. pub fn save(&mut self) { - let chain_type = self.members.server.chain_type; - let config_path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type)); + let config_path = Settings::get_config_path( + SERVER_CONFIG_FILE_NAME, + Some(&self.members.server.chain_type) + ); Settings::write_to_file(&self.members, config_path); } /// Check that the api secret files exist and are valid. fn check_api_secret_files( - chain_type: ChainTypes, + chain_type: &ChainTypes, secret_file_name: &str, ) -> Result<(), ConfigError> { let grin_path = Settings::get_working_path(Some(chain_type)); @@ -83,7 +85,7 @@ impl NodeConfig { } /// Get stratum server IP address and port. - pub fn get_stratum_address_port() -> (String, u16) { + pub fn get_stratum_address_port() -> (String, String) { let r_config = Settings::node_config_to_read(); let saved_stratum_addr = r_config .members @@ -95,11 +97,11 @@ impl NodeConfig { .as_ref() .unwrap(); let (addr, port) = saved_stratum_addr.split_once(":").unwrap(); - (addr.to_string(), port.parse().unwrap()) + (addr.into(), port.into()) } /// Save stratum server IP address and port. - pub fn save_stratum_address_port(addr: String, port: String) { + pub fn save_stratum_address_port(addr: &String, port: &String) { let addr_to_save = format!("{}:{}", addr, port); let mut w_node_config = Settings::node_config_to_update(); w_node_config @@ -112,8 +114,47 @@ impl NodeConfig { w_node_config.save(); } + /// Check if stratum mining server autorun is enabled. + pub fn is_stratum_autorun_enabled() -> bool { + let stratum_config = Settings::node_config_to_read() + .members + .clone() + .server + .stratum_mining_config + .unwrap(); + if let Some(enable) = stratum_config.enable_stratum_server { + return enable; + } + false + } + + /// Toggle stratum mining server autorun. + pub fn toggle_stratum_autorun() { + let autorun = Self::is_stratum_autorun_enabled(); + 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(!autorun); + 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, u16) { + pub fn get_api_address_port() -> (String, String) { let r_config = Settings::node_config_to_read(); let saved_api_addr = r_config .members @@ -121,11 +162,11 @@ impl NodeConfig { .api_http_addr .as_str(); let (addr, port) = saved_api_addr.split_once(":").unwrap(); - (addr.to_string(), port.parse().unwrap()) + (addr.into(), port.into()) } /// Save API server IP address and port. - pub fn save_api_server_address_port(addr: String, port: String) { + pub fn save_api_address_port(addr: &String, port: &String) { let addr_to_save = format!("{}:{}", addr, port); let mut w_node_config = Settings::node_config_to_update(); w_node_config.members.server.api_http_addr = addr_to_save; @@ -149,7 +190,7 @@ impl NodeConfig { } /// Save API secret text. - pub fn save_api_secret(api_secret: String) { + pub fn save_api_secret(api_secret: &String) { if api_secret.is_empty() { return; } @@ -181,7 +222,7 @@ impl NodeConfig { } /// Save Foreign API secret text. - pub fn save_foreign_api_secret(api_secret: String) { + pub fn save_foreign_api_secret(api_secret: &String) { if api_secret.is_empty() { return; } diff --git a/src/settings.rs b/src/settings.rs index 61bf3da..7cec7c3 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -65,11 +65,9 @@ impl AppConfig { } /// Change chain type and load new [`NodeConfig`] accordingly. - pub fn change_chain_type(&mut self, chain_type: ChainTypes) { - if self.chain_type == chain_type { - return; - } else { - self.chain_type = chain_type; + pub fn change_chain_type(&mut self, chain_type: &ChainTypes) { + if self.chain_type != *chain_type { + self.chain_type = *chain_type; self.save(); // Load config for selected chain type. @@ -95,10 +93,9 @@ impl Settings { /// Initialize settings with app and node configs. fn init() -> Self { let app_config = AppConfig::init(); - let chain_type = app_config.chain_type; Self { - app_config: Arc::new(RwLock::new(app_config)), - node_config: Arc::new(RwLock::new(NodeConfig::init(chain_type))) + node_config: Arc::new(RwLock::new(NodeConfig::init(&app_config.chain_type))), + app_config: Arc::new(RwLock::new(app_config)) } } @@ -123,7 +120,7 @@ impl Settings { } /// Get working directory path for the application. - pub fn get_working_path(chain_type: Option) -> PathBuf { + pub fn get_working_path(chain_type: Option<&ChainTypes>) -> PathBuf { // Check if dir exists. let mut path = match dirs::home_dir() { Some(p) => p, @@ -141,7 +138,7 @@ impl Settings { } /// Get config file path from provided name and [`ChainTypes`] if needed. - pub fn get_config_path(config_name: &str, chain_type: Option) -> PathBuf { + pub fn get_config_path(config_name: &str, chain_type: Option<&ChainTypes>) -> PathBuf { let main_path = Self::get_working_path(chain_type); let mut settings_path = main_path.clone(); settings_path.push(config_name);