ui + config: optimize ip list at config ui, api port modal, update, translations, better check ports availability, refactor settings initialization and arguments passing

This commit is contained in:
ardocrat 2023-06-29 03:42:03 +03:00
parent 8fdc2c1e39
commit 1a74678c67
11 changed files with 381 additions and 248 deletions

View file

@ -11,7 +11,7 @@ network:
restart: Restart restart: Restart
autorun: Autorun autorun: Autorun
disabled_server: 'Enable integrated node or add another connection method by pressing %{dots} in the top-left corner of the screen.' 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: sync_status:
node_restarting: Node is restarting node_restarting: Node is restarting
node_down: Node is down node_down: Node is down
@ -60,7 +60,6 @@ network_mining:
enable_server: Enable server 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.' 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.' 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 rewards_wallet: Wallet for rewards
server: Stratum server server: Stratum server
address: Address address: Address
@ -72,15 +71,17 @@ network_mining:
disconnected: Disconnected disconnected: Disconnected
network_settings: network_settings:
port: Port port: Port
ip_address: IP Address ip: IP Address
change_port: Change port change_port: Change port
enter_value: 'Enter value:' enter_value: Enter value
server: port_unavailable: Specified port is unavailable
title: Server restart_app_required: App restart is required to apply changes.
enable: Enable enable: Enable
disable: Disable disable: Disable
restart: Restart restart: Restart
api_ip_address: API IP Address server: Server
api_ip: API IP Address
api_port: API Port
modal: modal:
cancel: Cancel cancel: Cancel
save: Save save: Save

View file

@ -11,7 +11,7 @@ network:
restart: Перезапустить restart: Перезапустить
autorun: Автозапуск autorun: Автозапуск
disabled_server: 'Включите встроенный узел или добавьте другой способ подключения, нажав %{dots} в левом-верхнем углу экрана.' disabled_server: 'Включите встроенный узел или добавьте другой способ подключения, нажав %{dots} в левом-верхнем углу экрана.'
no_ip_addresses: В вашей системе отсутствуют доступные IP адреса, запуск сервера невозможен, проверьте ваше подключение к сети. no_ips: В вашей системе отсутствуют доступные IP адреса, запуск сервера невозможен, проверьте ваше подключение к сети.
sync_status: sync_status:
node_restarting: Узел перезапускается node_restarting: Узел перезапускается
node_down: Узел выключен node_down: Узел выключен
@ -60,7 +60,6 @@ network_mining:
enable_server: Включить сервер enable_server: Включить сервер
server_setting: 'Включите stratum-сервер или измените больше настроек, выбрав %{settings} внизу экрана. Для изменения настроек запущенного сервера потребуется перезапуск приложения.' server_setting: 'Включите stratum-сервер или измените больше настроек, выбрав %{settings} внизу экрана. Для изменения настроек запущенного сервера потребуется перезапуск приложения.'
info: 'Сервер майнинга запущен, вы можете изменить его настройки, выбрав %{settings} внизу экрана. Данные обновляются, когда устройства подключены.' info: 'Сервер майнинга запущен, вы можете изменить его настройки, выбрав %{settings} внизу экрана. Данные обновляются, когда устройства подключены.'
port_unavailable: Указанный порт недоступен
rewards_wallet: Кошелёк для наград rewards_wallet: Кошелёк для наград
server: Stratum-сервер server: Stratum-сервер
address: Адрес address: Адрес
@ -71,16 +70,18 @@ network_mining:
connected: Подключен connected: Подключен
disconnected: Отключен disconnected: Отключен
network_settings: network_settings:
ip_address: IP Адрес ip: IP Адрес
port: Порт port: Порт
change_port: Изменить порт change_port: Изменить порт
enter_value: 'Введите значение:' enter_value: Введите значение
server: port_unavailable: Указанный порт недоступен
title: Сервер restart_app_required: Для применения изменений требуется перезапуск приложения.
enable: Включить enable: Включить
disable: Выключить disable: Выключить
restart: Перезапустить restart: Перезапустить
api_ip_address: API IP Адрес server: Сервер
api_ip: API IP Адрес
api_port: API Порт
modal: modal:
cancel: Отмена cancel: Отмена
save: Сохранить save: Сохранить

View file

@ -45,7 +45,7 @@ impl Default for Root {
} }
impl ModalContainer 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() self.allowed_modal_ids.as_ref()
} }
} }

View file

@ -23,11 +23,12 @@ use crate::gui::views::View;
/// Contains modal ids to draw at current container if possible. /// Contains modal ids to draw at current container if possible.
pub trait ModalContainer { 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. /// Check if it's possible to show modal.
fn can_show_modal(&self, id: &'static str) -> bool { fn can_show_modal(&self, id: &'static str) -> bool {
self.allowed_modal_ids().contains(&id) self.modal_ids().contains(&id)
} }
} }

View file

@ -29,6 +29,7 @@ use crate::gui::views::network_metrics::NetworkMetrics;
use crate::gui::views::network_mining::NetworkMining; use crate::gui::views::network_mining::NetworkMining;
use crate::gui::views::network_node::NetworkNode; use crate::gui::views::network_node::NetworkNode;
use crate::gui::views::network_settings::NetworkSettings; use crate::gui::views::network_settings::NetworkSettings;
use crate::gui::views::settings_node::NodeSetup;
use crate::gui::views::settings_stratum::StratumServerSetup; use crate::gui::views::settings_stratum::StratumServerSetup;
use crate::node::Node; use crate::node::Node;
use crate::Settings; use crate::Settings;
@ -60,23 +61,24 @@ impl NetworkTabType {
pub struct Network { pub struct Network {
current_tab: Box<dyn NetworkTab>, current_tab: Box<dyn NetworkTab>,
allowed_modal_ids: Vec<&'static str>, modal_ids: Vec<&'static str>,
} }
impl Default for Network { impl Default for Network {
fn default() -> Self { fn default() -> Self {
Self { Self {
current_tab: Box::new(NetworkNode::default()), current_tab: Box::new(NetworkNode::default()),
allowed_modal_ids: vec![ modal_ids: vec![
StratumServerSetup::STRATUM_PORT_MODAL StratumServerSetup::STRATUM_PORT_MODAL,
NodeSetup::API_PORT_MODAL
] ]
} }
} }
} }
impl ModalContainer for Network { impl ModalContainer for Network {
fn allowed_modal_ids(&self) -> &Vec<&'static str> { fn modal_ids(&self) -> &Vec<&'static str> {
self.allowed_modal_ids.as_ref() self.modal_ids.as_ref()
} }
} }
@ -278,10 +280,57 @@ impl Network {
addresses addresses
} }
/// Draw IP list radio buttons.
pub fn ip_list_ui(ui: &mut egui::Ui,
saved_ip: &String,
ips: &Vec<IpAddr>,
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::<Vec<_>>();
if saved_ip_addr != selected_ip_addr {
(on_change)(&selected_ip_addr.to_string());
}
}
/// Show message when IP addresses are not available at system. /// Show message when IP addresses are not available at system.
pub fn no_ip_address_ui(ui: &mut egui::Ui) { pub fn no_ip_address_ui(ui: &mut egui::Ui) {
ui.vertical_centered(|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) .size(16.0)
.color(Colors::INACTIVE_TEXT) .color(Colors::INACTIVE_TEXT)
); );
@ -290,10 +339,13 @@ impl Network {
} }
/// Check whether a port is available on the provided host. /// Check whether a port is available on the provided host.
pub fn is_port_available(host: &str, port: u16) -> bool { pub fn is_port_available(host: &String, port: &String) -> bool {
let ip_addr = Ipv4Addr::from_str(host).unwrap(); if let Ok(p) = port.parse::<u16>() {
let ipv4 = SocketAddrV4::new(ip_addr, port); let ip_addr = Ipv4Addr::from_str(host.as_str()).unwrap();
TcpListener::bind(ipv4).is_ok() let ipv4 = SocketAddrV4::new(ip_addr, p);
return TcpListener::bind(ipv4).is_ok();
}
false
} }
} }

View file

@ -77,29 +77,21 @@ impl NetworkTab for NetworkMining {
ui.add_space(4.0); ui.add_space(4.0);
// Show button to enable stratum server if port is available. // 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); ui.add_space(6.0);
View::button(ui, t!("network_mining.enable_server"), Colors::GOLD, || { View::button(ui, t!("network_mining.enable_server"), Colors::GOLD, || {
Node::start_stratum_server(); Node::start_stratum_server();
}); });
ui.add_space(2.0); ui.add_space(2.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. // Show stratum server autorun checkbox.
let stratum_enabled = NodeConfig::is_stratum_autorun_enabled();
View::checkbox(ui, stratum_enabled, t!("network.autorun"), || { View::checkbox(ui, stratum_enabled, t!("network.autorun"), || {
let mut w_node_config = Settings::node_config_to_update(); NodeConfig::toggle_stratum_autorun();
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); ui.add_space(6.0);
}
});
}); });
return; return;
} else if Node::is_stratum_server_starting() { } else if Node::is_stratum_server_starting() {

View file

@ -37,6 +37,11 @@ impl NetworkTab for NetworkSettings {
} }
fn on_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) { 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);
},
_ => {}
}
} }
} }

View file

@ -14,24 +14,22 @@
use std::net::IpAddr; use std::net::IpAddr;
use std::str::FromStr; use std::str::FromStr;
use egui::RichText; use egui::{RichText, TextStyle, Widget};
use crate::gui::Colors; use crate::gui::{Colors, Navigator};
use crate::gui::icons::COMPUTER_TOWER; use crate::gui::icons::{COMPUTER_TOWER, POWER};
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Network, View}; use crate::gui::views::{Modal, ModalPosition, Network, View};
use crate::node::{Node, NodeConfig}; use crate::node::{Node, NodeConfig};
/// Integrated node server setup ui section. /// Integrated node server setup ui section.
pub struct NodeSetup { 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 to be used inside edit modal.
api_port_edit: String, api_port_edit: String,
/// Flag to check if API port is available inside edit modal. /// Flag to check if API port is available inside edit modal.
api_port_available_edit: bool, api_port_available_edit: bool,
/// Flag to check if API port is available from saved config value. /// 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 to be used inside edit modal.
api_secret_edit: String, api_secret_edit: String,
@ -45,13 +43,12 @@ pub struct NodeSetup {
impl Default for NodeSetup { impl Default for NodeSetup {
fn default() -> Self { fn default() -> Self {
let (api_address, api_port) = NodeConfig::get_api_address_port(); let (api_ip, api_port) = NodeConfig::get_api_address_port();
let is_api_port_available = Network::is_port_available(api_address.as_str(), api_port); let is_api_port_available = is_api_port_available(&api_ip, &api_port);
Self { Self {
api_address_edit: api_address, api_port_edit: api_port,
api_port_edit: api_port.to_string(),
api_port_available_edit: is_api_port_available, api_port_available_edit: is_api_port_available,
api_port_available: is_api_port_available, is_api_port_available,
api_secret_edit: "".to_string(), api_secret_edit: "".to_string(),
foreign_api_secret_edit: "".to_string(), foreign_api_secret_edit: "".to_string(),
ftl_edit: "".to_string(), ftl_edit: "".to_string(),
@ -62,10 +59,10 @@ impl Default for NodeSetup {
const SECRET_SYMBOLS: &'static str = "••••••••••••"; const SECRET_SYMBOLS: &'static str = "••••••••••••";
impl NodeSetup { 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) { 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); View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(4.0); ui.add_space(4.0);
@ -79,17 +76,17 @@ impl NodeSetup {
if Node::is_running() { if Node::is_running() {
ui.scope(|ui| { ui.scope(|ui| {
// Setup spacing between buttons. // 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.add_space(6.0);
ui.columns(2, |columns| { ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| { 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); Node::stop(false);
}); });
}); });
columns[1].vertical_centered_justified(|ui| { 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(); Node::restart();
}); });
}); });
@ -98,7 +95,8 @@ impl NodeSetup {
} else { } else {
ui.add_space(6.0); ui.add_space(6.0);
ui.vertical_centered(|ui| { 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(); Node::start();
}); });
}); });
@ -112,7 +110,7 @@ impl NodeSetup {
ui.add_space(4.0); ui.add_space(4.0);
let addrs = Network::get_ip_list(); 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() { if addrs.is_empty() {
Network::no_ip_address_ui(ui); Network::no_ip_address_ui(ui);
ui.add_space(4.0); ui.add_space(4.0);
@ -121,63 +119,146 @@ impl NodeSetup {
ui.add_space(4.0); ui.add_space(4.0);
ui.vertical_centered(|ui| { 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) .size(16.0)
.color(Colors::GRAY) .color(Colors::GRAY)
); );
ui.add_space(6.0); ui.add_space(6.0);
// 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);
}); });
// Show API IP address setup. ui.label(RichText::new(t!("network_settings.api_port"))
self.api_ip_address_setup_ui(ui, addrs) .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);
});
} }
} }
/// Show API IP address setup. /// Draw API port setup ui.
fn api_ip_address_setup_ui(&mut self, ui: &mut egui::Ui, addrs: Vec<IpAddr>) { fn api_port_setup_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
let (addr, port) = NodeConfig::get_api_address_port(); let (_, port) = NodeConfig::get_api_address_port();
let saved_ip_addr = &IpAddr::from_str(addr.as_str()).unwrap(); // Show button to choose API server port.
let mut selected_addr = saved_ip_addr; 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;
// Set first IP address as current if saved is not present at system. // Show API port modal.
if !addrs.contains(selected_addr) { let port_modal = Modal::new(Self::API_PORT_MODAL)
selected_addr = addrs.get(0).unwrap(); .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);
}
} }
// Show available IP addresses on the system. /// Draw API port [`Modal`] content ui.
let _ = addrs.chunks(2).map(|x| { pub fn api_port_modal_ui(&mut self,
if x.len() == 2 { 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| { ui.columns(2, |columns| {
let addr0 = x.get(0).unwrap(); columns[0].vertical_centered_justified(|ui| {
columns[0].vertical_centered(|ui| { View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
View::radio_value(ui, cb.hide_keyboard();
&mut selected_addr, modal.close();
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());
})
}); });
} else { columns[1].vertical_centered_justified(|ui| {
let addr = x.get(0).unwrap(); View::button(ui, t!("modal.save"), Colors::WHITE, || {
View::radio_value(ui, // Check if port is available.
&mut selected_addr, let (ip, _) = NodeConfig::get_api_address_port();
addr, let available = is_api_port_available(&ip, &self.api_port_edit);
addr.to_string()); self.api_port_available_edit = available;
}
ui.add_space(10.0);
}).collect::<Vec<_>>();
// Save stratum server address at config if it was changed and check port availability. if self.api_port_available_edit {
if saved_ip_addr != selected_addr { // Save port at config if it's available.
NodeConfig::save_api_server_address_port(selected_addr.to_string(), port.to_string()); NodeConfig::save_api_address_port(
let available = Network::is_port_available(selected_addr.to_string().as_str(), port); &ip,
self.api_port_available = available; &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() && &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

@ -22,29 +22,27 @@ use crate::gui::icons::WRENCH;
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, ModalPosition, Network, View}; use crate::gui::views::{Modal, ModalPosition, Network, View};
use crate::node::NodeConfig; use crate::node::NodeConfig;
use crate::Settings;
/// Stratum server setup ui section. /// Stratum server setup ui section.
pub struct StratumServerSetup { 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 to be used inside edit modal.
stratum_port_edit: String, stratum_port_edit: String,
/// Flag to check if stratum port is available inside edit modal. /// Flag to check if stratum port is available inside edit modal.
stratum_port_available_edit: bool, stratum_port_available_edit: bool,
/// Flag to check if stratum port is available from saved config value. /// 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 { impl Default for StratumServerSetup {
fn default() -> Self { fn default() -> Self {
let (stratum_address, stratum_port) = NodeConfig::get_stratum_address_port(); let (ip, port) = NodeConfig::get_stratum_address_port();
let is_port_available = Network::is_port_available(stratum_address.as_str(), stratum_port); let is_port_available = is_stratum_port_available(&ip, &port);
Self { Self {
stratum_address_edit: stratum_address, stratum_port_edit: port,
stratum_port_edit: stratum_port.to_string(),
stratum_port_available_edit: is_port_available, stratum_port_available_edit: is_port_available,
is_stratum_port_available: is_port_available is_port_available
} }
} }
} }
@ -58,42 +56,50 @@ impl StratumServerSetup {
View::horizontal_line(ui, Colors::ITEM_STROKE); View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(4.0); ui.add_space(4.0);
// Show error message when IP addresses are not available on the system. // Show message when IP addresses are not available on the system.
let addrs = Network::get_ip_list(); let all_ips = Network::get_ip_list();
if addrs.is_empty() { if all_ips.is_empty() {
Network::no_ip_address_ui(ui); Network::no_ip_address_ui(ui);
return; return;
} }
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network_settings.ip_address")) ui.label(RichText::new(t!("network_settings.ip"))
.size(16.0) .size(16.0)
.color(Colors::GRAY) .color(Colors::GRAY)
); );
ui.add_space(6.0); ui.add_space(6.0);
// Show stratum IP addresses to select.
// Show stratum IP address setup. let (ip, port) = NodeConfig::get_stratum_address_port();
self.ip_address_setup_ui(ui, addrs); Network::ip_list_ui(ui, &ip, &all_ips, |selected_ip| {
self.is_port_available = is_stratum_port_available(selected_ip, &port);
View::horizontal_line(ui, Colors::ITEM_STROKE); NodeConfig::save_stratum_address_port(selected_ip, &port);
ui.add_space(6.0); 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"))
.size(16.0) .size(16.0)
.color(Colors::GRAY) .color(Colors::GRAY)
); );
// Show button to choose stratum server port.
ui.add_space(6.0); ui.add_space(6.0);
let (stratum_address, stratum_port) = NodeConfig::get_stratum_address_port(); // Show stratum port setup.
View::button(ui, stratum_port.to_string(), Colors::BUTTON, || { self.port_setup_ui(ui, cb);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
});
}
/// 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. // Setup values for modal.
self.stratum_address_edit = stratum_address.clone(); self.stratum_port_edit = port;
self.stratum_port_edit = stratum_port.to_string(); self.stratum_port_available_edit = self.is_port_available;
self.stratum_port_available_edit = Network::is_port_available(
stratum_address.as_str(),
stratum_port
);
// Show stratum port modal. // Show stratum port modal.
let port_modal = Modal::new(Self::STRATUM_PORT_MODAL) let port_modal = Modal::new(Self::STRATUM_PORT_MODAL)
@ -105,19 +111,15 @@ impl StratumServerSetup {
ui.add_space(14.0); ui.add_space(14.0);
// Show error when stratum server port is unavailable. // Show error when stratum server port is unavailable.
if !self.is_stratum_port_available { if !self.is_port_available {
ui.label(RichText::new(t!("network_mining.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(12.0);
} }
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
});
} }
/// Draw stratum port [`Modal`] content. /// Draw stratum port [`Modal`] content ui.
pub fn stratum_port_modal_ui(&mut self, pub fn stratum_port_modal_ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
modal: &Modal, modal: &Modal,
@ -143,7 +145,7 @@ impl StratumServerSetup {
// Show error when specified port is unavailable. // Show error when specified port is unavailable.
if !self.stratum_port_available_edit { if !self.stratum_port_available_edit {
ui.add_space(12.0); 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) .size(16.0)
.color(Colors::RED)); .color(Colors::RED));
} }
@ -153,7 +155,7 @@ impl StratumServerSetup {
// Show modal buttons. // Show modal buttons.
ui.scope(|ui| { ui.scope(|ui| {
// Setup spacing between buttons. // 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| { ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| { columns[0].vertical_centered_justified(|ui| {
@ -166,21 +168,15 @@ impl StratumServerSetup {
columns[1].vertical_centered_justified(|ui| { columns[1].vertical_centered_justified(|ui| {
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 port_parse = self.stratum_port_edit.parse::<u16>(); let (ip, _) = NodeConfig::get_api_address_port();
let is_available = port_parse.is_ok() && Network::is_port_available( let available = is_stratum_port_available(&ip, &self.stratum_port_edit);
self.stratum_address_edit.as_str(), self.stratum_port_available_edit = available;
port_parse.unwrap()
);
self.stratum_port_available_edit = is_available;
// Save port at config if it's available. // Save port at config if it's available.
if self.stratum_port_available_edit { if self.stratum_port_available_edit {
NodeConfig::save_stratum_address_port( NodeConfig::save_stratum_address_port(&ip, &self.stratum_port_edit);
self.stratum_address_edit.clone(),
self.stratum_port_edit.clone()
);
self.is_stratum_port_available = true; self.is_port_available = true;
cb.hide_keyboard(); cb.hide_keyboard();
modal.close(); 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<IpAddr>) { fn is_stratum_port_available(ip: &String, port: &String) -> bool {
let (addr, port) = NodeConfig::get_stratum_address_port(); if Network::is_port_available(&ip, &port) {
let saved_ip_addr = &IpAddr::from_str(addr.as_str()).unwrap(); if &NodeConfig::get_p2p_port().to_string() != port {
let mut selected_addr = saved_ip_addr; let (api_ip, api_port) = NodeConfig::get_api_address_port();
return if &api_ip == ip {
// Set first IP address as current if saved is not present at system. &api_port != port
if !addrs.contains(selected_addr) { } else {
selected_addr = addrs.get(0).unwrap(); true
} }
}
// Show available IP addresses on the system. }
let _ = addrs.chunks(2).map(|x| { false
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());
})
});
} else {
let addr = x.get(0).unwrap();
View::radio_value(ui,
&mut selected_addr,
addr,
addr.to_string());
}
ui.add_space(10.0);
}).collect::<Vec<_>>();
// 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;
}
}
} }

View file

@ -35,7 +35,7 @@ pub struct NodeConfig {
impl NodeConfig { impl NodeConfig {
/// Initialize integrated node config. /// 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, API_SECRET_FILE_NAME);
let _ = Self::check_api_secret_files(chain_type, FOREIGN_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`]. /// 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 path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type));
let parsed = Settings::read_from_file::<ConfigMembers>(path.clone()); let parsed = Settings::read_from_file::<ConfigMembers>(path.clone());
if !path.exists() || parsed.is_err() { 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))); default_config.update_paths(&Settings::get_working_path(Some(chain_type)));
let config = default_config.members.unwrap(); let config = default_config.members.unwrap();
Settings::write_to_file(&config, path); Settings::write_to_file(&config, path);
@ -62,14 +62,16 @@ impl NodeConfig {
/// Save node config to disk. /// Save node config to disk.
pub fn save(&mut self) { pub fn save(&mut self) {
let chain_type = self.members.server.chain_type; let config_path = Settings::get_config_path(
let config_path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type)); SERVER_CONFIG_FILE_NAME,
Some(&self.members.server.chain_type)
);
Settings::write_to_file(&self.members, config_path); Settings::write_to_file(&self.members, config_path);
} }
/// 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,
secret_file_name: &str, secret_file_name: &str,
) -> Result<(), ConfigError> { ) -> Result<(), ConfigError> {
let grin_path = Settings::get_working_path(Some(chain_type)); let grin_path = Settings::get_working_path(Some(chain_type));
@ -83,7 +85,7 @@ impl NodeConfig {
} }
/// Get stratum server IP address and port. /// 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 r_config = Settings::node_config_to_read();
let saved_stratum_addr = r_config let saved_stratum_addr = r_config
.members .members
@ -95,11 +97,11 @@ impl NodeConfig {
.as_ref() .as_ref()
.unwrap(); .unwrap();
let (addr, port) = saved_stratum_addr.split_once(":").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. /// 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 addr_to_save = format!("{}:{}", addr, port);
let mut w_node_config = Settings::node_config_to_update(); let mut w_node_config = Settings::node_config_to_update();
w_node_config w_node_config
@ -112,8 +114,47 @@ impl NodeConfig {
w_node_config.save(); 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. /// 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 r_config = Settings::node_config_to_read();
let saved_api_addr = r_config let saved_api_addr = r_config
.members .members
@ -121,11 +162,11 @@ impl NodeConfig {
.api_http_addr .api_http_addr
.as_str(); .as_str();
let (addr, port) = saved_api_addr.split_once(":").unwrap(); 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. /// 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 addr_to_save = format!("{}:{}", addr, port);
let mut w_node_config = Settings::node_config_to_update(); let mut w_node_config = Settings::node_config_to_update();
w_node_config.members.server.api_http_addr = addr_to_save; w_node_config.members.server.api_http_addr = addr_to_save;
@ -149,7 +190,7 @@ impl NodeConfig {
} }
/// Save API secret text. /// 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() { if api_secret.is_empty() {
return; return;
} }
@ -181,7 +222,7 @@ impl NodeConfig {
} }
/// Save Foreign API secret text. /// 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() { if api_secret.is_empty() {
return; return;
} }

View file

@ -65,11 +65,9 @@ impl AppConfig {
} }
/// Change chain type and load new [`NodeConfig`] accordingly. /// Change chain type and load new [`NodeConfig`] accordingly.
pub fn change_chain_type(&mut self, chain_type: ChainTypes) { pub fn change_chain_type(&mut self, chain_type: &ChainTypes) {
if self.chain_type == chain_type { if self.chain_type != *chain_type {
return; self.chain_type = *chain_type;
} else {
self.chain_type = chain_type;
self.save(); self.save();
// Load config for selected chain type. // Load config for selected chain type.
@ -95,10 +93,9 @@ impl Settings {
/// Initialize settings with app and node configs. /// Initialize settings with app and node configs.
fn init() -> Self { fn init() -> Self {
let app_config = AppConfig::init(); let app_config = AppConfig::init();
let chain_type = app_config.chain_type;
Self { Self {
app_config: Arc::new(RwLock::new(app_config)), node_config: Arc::new(RwLock::new(NodeConfig::init(&app_config.chain_type))),
node_config: Arc::new(RwLock::new(NodeConfig::init(chain_type))) app_config: Arc::new(RwLock::new(app_config))
} }
} }
@ -123,7 +120,7 @@ impl Settings {
} }
/// Get working directory path for the application. /// Get working directory path for the application.
pub fn get_working_path(chain_type: Option<ChainTypes>) -> PathBuf { pub fn get_working_path(chain_type: Option<&ChainTypes>) -> PathBuf {
// Check if dir exists. // Check if dir exists.
let mut path = match dirs::home_dir() { let mut path = match dirs::home_dir() {
Some(p) => p, Some(p) => p,
@ -141,7 +138,7 @@ impl Settings {
} }
/// Get config file path from provided name and [`ChainTypes`] if needed. /// Get config file path from provided name and [`ChainTypes`] if needed.
pub fn get_config_path(config_name: &str, chain_type: Option<ChainTypes>) -> PathBuf { pub fn get_config_path(config_name: &str, chain_type: Option<&ChainTypes>) -> PathBuf {
let main_path = Self::get_working_path(chain_type); let main_path = Self::get_working_path(chain_type);
let mut settings_path = main_path.clone(); let mut settings_path = main_path.clone();
settings_path.push(config_name); settings_path.push(config_name);