config + ui: fix network change, optimize api secrets, add api secrets and ftl ui, refactor settings ui, fix exit modal message font size, update translations

This commit is contained in:
ardocrat 2023-07-01 03:29:05 +03:00
parent 5bf09e4350
commit 6e6bb24e7d
12 changed files with 715 additions and 280 deletions

View file

@ -70,23 +70,31 @@ network_mining:
connected: Connected
disconnected: Disconnected
network_settings:
port: Port
ip: IP Address
port: Port
change_port: Change port
enter_value: Enter value
change_value: Change value
stratum_port: Stratum server port
port_unavailable: Specified port is unavailable
restart_app_required: App restart is required to apply changes.
restart_node_required: Node server restart is required to apply changes.
restart_node_required: Node restart is required to apply changes.
enable: Enable
disable: Disable
restart: Restart
server: Server
api_ip: API IP Address
api_port: API Port
api_secret: Rest API and V2 Owner API token
foreign_api_secret: Foreign API token
disabled: Disabled
copy: Copy
paste: Paste
ftl: The Future Time Limit (FTL)
ftl_description: Limit on how far into the future, relative to a node's local time in seconds, the timestamp on a new block can be, in order for the block to be accepted.
not_valid_value: Entered value is not valid
modal:
cancel: Cancel
save: Save
confirmation: Confirmation
modal_exit:
description: Are you sure you want to quit the application?
exit: Exit

View file

@ -65,7 +65,7 @@ network_mining:
address: Адрес
miners: Майнеры
devices: Устройства
found: Найдено
blocks_found: Найдено блоков
hashrate: 'Хешрэйт (C%{bits})'
connected: Подключен
disconnected: Отключен
@ -73,7 +73,8 @@ network_settings:
ip: IP Адрес
port: Порт
change_port: Изменить порт
enter_value: Введите значение
change_value: Изменить значение
stratum_port: Порт Stratum сервера
port_unavailable: Указанный порт недоступен
restart_app_required: Для применения изменений требуется перезапуск приложения.
restart_node_required: Для применения изменений требуется перезапуск узла.
@ -83,10 +84,17 @@ network_settings:
server: Сервер
api_ip: API IP Адрес
api_port: API Порт
api_secret: Rest и V2 Owner API токен
foreign_api_secret: Foreign API токен
disabled: Отключен
copy: Копировать
paste: Вставить
ftl: Предел Будущего Времени (FTL)
ftl_description: Ограничение на то, насколько далеко в будущем, относительно локального времени узла в секундах, находится временная метка на новом блоке для его принятия.
not_valid_value: Введено недопустимое значение
modal:
cancel: Отмена
save: Сохранить
confirmation: Подтверждение
modal_exit:
description: Вы уверены, что хотите выйти из приложения?
exit: Выход

View file

@ -26,7 +26,7 @@ lazy_static! {
static ref NAVIGATOR_STATE: RwLock<Navigator> = RwLock::new(Navigator::default());
}
/// Logic of navigation at ui, stores screen identifiers stack, showing modal and side panel state.
/// Logic of common navigation at ui for screens and modals.
pub struct Navigator {
/// Screen identifiers in navigation stack.
screen_stack: BTreeSet<ScreenId>,
@ -81,7 +81,7 @@ impl Navigator {
return;
}
// Go back at screen stack or set exit confirmation Modal.
// Go back at screen stack or show exit confirmation Modal.
if w_nav.screen_stack.len() > 1 {
w_nav.screen_stack.pop_last();
} else {
@ -97,7 +97,7 @@ impl Navigator {
/// Set exit confirmation [`Modal`] with provided [NAVIGATOR_STATE] lock.
fn show_exit_modal_nav(mut w_nav: RwLockWriteGuard<Navigator>) {
let m = Modal::new(Self::EXIT_MODAL).title(t!("modal.confirmation"));
let m = Modal::new(Self::EXIT_MODAL).title(t!("modal_exit.exit"));
w_nav.modal = Some(m);
}

View file

@ -13,6 +13,7 @@
// limitations under the License.
use std::cmp::min;
use egui::RichText;
use crate::gui::{App, Colors, Navigator};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::screens::{Account, Accounts, Screen, ScreenId};
@ -88,13 +89,17 @@ impl Root {
ui.vertical_centered(|ui| {
View::small_loading_spinner(ui);
ui.add_space(12.0);
ui.label(t!("sync_status.shutdown"));
ui.label(RichText::new(t!("sync_status.shutdown"))
.size(18.0)
.color(Colors::TEXT));
});
ui.add_space(10.0);
} else {
ui.add_space(8.0);
ui.vertical_centered(|ui| {
ui.label(t!("modal_exit.description"));
ui.label(RichText::new(t!("modal_exit.description"))
.size(18.0)
.color(Colors::TEXT));
});
ui.add_space(10.0);

View file

@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::net::{IpAddr, Ipv4Addr, SocketAddrV4, TcpListener};
use std::str::FromStr;
use std::time::Duration;
use egui::{Color32, lerp, Rgba, RichText};
use egui::style::Margin;
use egui_extras::{Size, StripBuilder};
use grin_chain::SyncStatus;
use crate::AppConfig;
use crate::gui::{Colors, Navigator};
use crate::gui::icons::{CARDHOLDER, DATABASE, DOTS_THREE_OUTLINE_VERTICAL, FACTORY, FADERS, GAUGE};
@ -32,7 +31,6 @@ 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;
pub trait NetworkTab {
fn get_type(&self) -> NetworkTabType;
@ -69,8 +67,12 @@ impl Default for Network {
Self {
current_tab: Box::new(NetworkNode::default()),
modal_ids: vec![
NetworkSettings::NODE_RESTART_REQUIRED_MODAL,
StratumServerSetup::STRATUM_PORT_MODAL,
NodeSetup::API_PORT_MODAL
NodeSetup::API_PORT_MODAL,
NodeSetup::API_SECRET_MODAL,
NodeSetup::FOREIGN_API_SECRET_MODAL,
NodeSetup::FTL_MODAL
]
}
}
@ -101,7 +103,7 @@ impl Network {
..Default::default()
})
.show_inside(ui, |ui| {
self.draw_title(ui, frame);
self.title_ui(ui, frame);
});
egui::TopBottomPanel::bottom("network_tabs")
@ -110,7 +112,7 @@ impl Network {
..Default::default()
})
.show_inside(ui, |ui| {
self.draw_tabs(ui);
self.tabs_ui(ui);
});
egui::CentralPanel::default()
@ -125,7 +127,8 @@ impl Network {
});
}
fn draw_tabs(&mut self, ui: &mut egui::Ui) {
/// Draw tab buttons in the bottom of the screen.
fn tabs_ui(&mut self, ui: &mut egui::Ui) {
ui.scope(|ui| {
// Setup spacing between tabs.
ui.style_mut().spacing.item_spacing = egui::vec2(5.0, 0.0);
@ -157,11 +160,13 @@ impl Network {
});
}
/// Check if current tab equals providing [`NetworkTabType`].
fn is_current_tab(&self, tab_type: NetworkTabType) -> bool {
self.current_tab.get_type() == tab_type
}
fn draw_title(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
/// Draw title content.
fn title_ui(&mut self, ui: &mut egui::Ui, frame: &mut eframe::Frame) {
StripBuilder::new(ui)
.size(Size::exact(52.0))
.vertical(|mut strip| {
@ -179,7 +184,7 @@ impl Network {
});
});
strip.strip(|builder| {
self.draw_title_text(builder);
self.title_text_ui(builder);
});
strip.cell(|ui| {
if !View::is_dual_panel_mode(frame) {
@ -195,7 +200,8 @@ impl Network {
});
}
fn draw_title_text(&self, builder: StripBuilder) {
/// Draw title text.
fn title_text_ui(&self, builder: StripBuilder) {
builder
.size(Size::remainder())
.size(Size::exact(32.0))
@ -214,8 +220,8 @@ impl Network {
// Setup text color animation based on sync status
let idle = match sync_status {
None => { !Node::is_starting() }
Some(ss) => { ss == SyncStatus::NoSync }
None => !Node::is_starting(),
Some(ss) => ss == SyncStatus::NoSync
};
let (dark, bright) = (0.3, 1.0);
let color_factor = if !idle {
@ -253,89 +259,15 @@ impl Network {
Node::start();
});
ui.add_space(2.0);
Self::autorun_node_checkbox(ui);
Self::autorun_node_ui(ui);
});
}
/// Draw checkbox with setting to run node on app launch.
pub fn autorun_node_checkbox(ui: &mut egui::Ui) {
let autostart: bool = Settings::app_config_to_read().auto_start_node;
pub fn autorun_node_ui(ui: &mut egui::Ui) {
let autostart = AppConfig::autostart_node();
View::checkbox(ui, autostart, t!("network.autorun"), || {
let mut w_app_config = Settings::app_config_to_update();
w_app_config.auto_start_node = !autostart;
w_app_config.save();
AppConfig::toggle_node_autostart();
});
}
/// List of available IP addresses.
pub fn get_ip_list() -> Vec<IpAddr> {
let mut addresses = Vec::new();
for net_if in pnet::datalink::interfaces() {
for ip in net_if.ips {
if ip.is_ipv4() {
addresses.push(ip.ip());
}
}
}
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.
pub fn no_ip_address_ui(ui: &mut egui::Ui) {
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network.no_ips"))
.size(16.0)
.color(Colors::INACTIVE_TEXT)
);
ui.add_space(6.0);
});
}
}
}

View file

@ -23,7 +23,6 @@ use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, Network, NetworkTab, NetworkTabType, View};
use crate::gui::views::settings_stratum::StratumServerSetup;
use crate::node::{Node, NodeConfig};
use crate::Settings;
#[derive(Default)]
pub struct NetworkMining {
@ -38,7 +37,7 @@ impl NetworkTab for NetworkMining {
fn ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
let server_stats = Node::get_stats();
// Show message when node is not running or loading spinner when mining are not available.
// Show message when node is not running or loading spinner when mining is not available.
if !server_stats.is_some() || Node::get_sync_status().unwrap() != SyncStatus::NoSync {
if !Node::is_running() {
Network::disabled_node_ui(ui);
@ -105,7 +104,7 @@ impl NetworkTab for NetworkMining {
View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network_mining.server")));
ui.columns(2, |columns| {
columns[0].vertical_centered(|ui| {
let (stratum_addr, stratum_port) = NodeConfig::get_stratum_address_port();
let (stratum_addr, stratum_port) = NodeConfig::get_stratum_address();
View::rounded_box(ui,
format!("{}:{}", stratum_addr, stratum_port),
t!("network_mining.address"),
@ -256,8 +255,8 @@ fn draw_workers_stats(ui: &mut egui::Ui, ws: &WorkerStats, rounding: [bool; 2])
ui.add_space(2.0);
ui.horizontal_top(|ui| {
let (status_text, status_icon, status_color) = match ws.is_connected {
true => { (t!("network_mining.connected"), PLUGS_CONNECTED, Colors::BLACK) }
false => { (t!("network_mining.disconnected"), PLUGS, Colors::INACTIVE_TEXT) }
true => (t!("network_mining.connected"), PLUGS_CONNECTED, Colors::BLACK),
false => (t!("network_mining.disconnected"), PLUGS, Colors::INACTIVE_TEXT)
};
ui.add_space(5.0);
ui.heading(RichText::new(status_icon)

View file

@ -33,7 +33,7 @@ impl NetworkTab for NetworkNode {
fn ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
let server_stats = Node::get_stats();
// Show message when node is not running or loading spinner when stats are not available.
if !server_stats.is_some() {
if !server_stats.is_some() || Node::is_restarting() {
if !Node::is_running() {
Network::disabled_node_ui(ui);
} else {
@ -121,10 +121,8 @@ impl NetworkTab for NetworkNode {
ui.columns(2, |columns| {
columns[0].vertical_centered(|ui| {
let tx_stat = match &stats.tx_stats {
None => { "0 (0)".to_string() }
Some(tx) => {
format!("{} ({})", tx.tx_pool_size, tx.tx_pool_kernels)
}
None => "0 (0)".to_string(),
Some(tx) => format!("{} ({})", tx.tx_pool_size, tx.tx_pool_kernels)
};
View::rounded_box(ui,
tx_stat,
@ -133,10 +131,10 @@ impl NetworkTab for NetworkNode {
});
columns[1].vertical_centered(|ui| {
let stem_tx_stat = match &stats.tx_stats {
None => { "0 (0)".to_string() }
Some(stx) => {
format!("{} ({})", stx.stem_pool_size, stx.stem_pool_kernels)
}
None => "0 (0)".to_string(),
Some(stx) => format!("{} ({})",
stx.stem_pool_size,
stx.stem_pool_kernels)
};
View::rounded_box(ui,
stem_tx_stat,

View file

@ -12,10 +12,16 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use egui::ScrollArea;
use std::net::IpAddr;
use std::str::FromStr;
use egui::{RichText, ScrollArea};
use crate::gui::Colors;
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, NetworkTab, NetworkTabType};
use crate::gui::views::{Modal, NetworkTab, NetworkTabType, View};
use crate::gui::views::settings_node::NodeSetup;
use crate::node::Node;
#[derive(Default)]
pub struct NetworkSettings {
@ -38,10 +44,129 @@ impl NetworkTab for NetworkSettings {
fn on_modal_ui(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
match modal.id {
Self::NODE_RESTART_REQUIRED_MODAL => {
self.node_restart_required_modal(ui, modal);
}
NodeSetup::API_PORT_MODAL => {
self.node_setup.api_port_modal_ui(ui, modal, cb);
self.node_setup.api_port_modal(ui, modal, cb);
},
NodeSetup::API_SECRET_MODAL => {
self.node_setup.secret_modal(ui, modal, cb);
},
NodeSetup::FOREIGN_API_SECRET_MODAL => {
self.node_setup.secret_modal(ui, modal, cb);
},
NodeSetup::FTL_MODAL => {
self.node_setup.ftl_modal(ui, modal, cb);
}
_ => {}
}
}
}
impl NetworkSettings {
pub const NODE_RESTART_REQUIRED_MODAL: &'static str = "node_restart_required";
/// Node restart reminder modal content.
pub fn node_restart_required_modal(&self, ui: &mut egui::Ui, modal: &Modal) {
ui.add_space(6.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(18.0)
.color(Colors::GRAY));
ui.add_space(8.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!("network_settings.restart"), Colors::WHITE, || {
Node::restart();
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
modal.close();
});
});
});
ui.add_space(6.0);
});
}
/// List of available IP addresses.
pub fn get_ip_addrs() -> Vec<IpAddr> {
let mut ip_addrs = Vec::new();
for net_if in pnet::datalink::interfaces() {
for ip in net_if.ips {
if ip.is_ipv4() {
ip_addrs.push(ip.ip());
}
}
}
ip_addrs
}
/// Draw IP addresses as radio buttons.
pub fn ip_addrs_ui(ui: &mut egui::Ui,
saved_ip: &String,
ip_addrs: &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 !ip_addrs.contains(selected_ip_addr) {
selected_ip_addr = ip_addrs.get(0).unwrap();
}
// Show available IP addresses on the system.
let _ = ip_addrs.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.
pub fn no_ip_address_ui(ui: &mut egui::Ui) {
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network.no_ips"))
.size(16.0)
.color(Colors::INACTIVE_TEXT)
);
ui.add_space(6.0);
});
}
}

View file

@ -12,13 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::net::IpAddr;
use std::str::FromStr;
use egui::{RichText, TextStyle, Widget};
use eframe::emath::Align;
use egui::{Id, Layout, RichText, TextStyle, Widget};
use grin_core::global::ChainTypes;
use crate::AppConfig;
use crate::gui::{Colors, Navigator};
use crate::gui::icons::{COMPUTER_TOWER, POWER};
use crate::gui::icons::{ASTERISK, CLIPBOARD_TEXT, COMPUTER_TOWER, COPY, POWER};
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, ModalPosition, Network, View};
use crate::gui::views::network_settings::NetworkSettings;
use crate::node::{Node, NodeConfig};
/// Integrated node server setup ui section.
@ -43,7 +45,7 @@ pub struct NodeSetup {
impl Default for NodeSetup {
fn default() -> Self {
let (api_ip, api_port) = NodeConfig::get_api_address_port();
let (api_ip, api_port) = NodeConfig::get_api_address();
let is_api_port_available = NodeConfig::is_api_port_available(&api_ip, &api_port);
Self {
api_port_edit: api_port,
@ -56,15 +58,19 @@ impl Default for NodeSetup {
}
}
const SECRET_SYMBOLS: &'static str = "••••••••••••";
impl NodeSetup {
pub const API_PORT_MODAL: &'static str = "api_port";
pub const API_SECRET_MODAL: &'static str = "api_secret";
pub const FOREIGN_API_SECRET_MODAL: &'static str = "foreign_api_secret";
pub const FTL_MODAL: &'static str = "ftl";
pub fn ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
View::sub_title(ui, format!("{} {}", COMPUTER_TOWER, t!("network_settings.server")));
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(4.0);
ui.add_space(8.0);
// Show chain type setup.
self.chain_type_ui(ui);
// Show loading indicator or controls to stop/start/restart node.
if Node::is_stopping() || Node::is_restarting() || Node::is_starting() {
@ -103,16 +109,18 @@ impl NodeSetup {
}
}
// Autorun node setup.
ui.add_space(4.0);
ui.vertical_centered(|ui| {
Network::autorun_node_checkbox(ui);
Network::autorun_node_ui(ui);
});
ui.add_space(4.0);
let addrs = Network::get_ip_list();
// Show message when IP addresses are not available on the system.
let addrs = NetworkSettings::get_ip_addrs();
if addrs.is_empty() {
Network::no_ip_address_ui(ui);
// Show message when IP addresses are not available on the system.
NetworkSettings::no_ip_address_ui(ui);
ui.add_space(4.0);
} else {
View::horizontal_line(ui, Colors::ITEM_STROKE);
@ -125,15 +133,11 @@ impl NodeSetup {
);
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| {
println!("12345 selected_ip {}", selected_ip);
let (api_ip, api_port) = NodeConfig::get_api_address();
NetworkSettings::ip_addrs_ui(ui, &api_ip, &addrs, |selected_ip| {
let api_available = NodeConfig::is_api_port_available(selected_ip, &api_port);
println!("12345 selected_ip is_api_port_available {}", api_available);
self.is_api_port_available = api_available;
println!("12345 before save");
NodeConfig::save_api_address_port(selected_ip, &api_port);
println!("12345 after save");
NodeConfig::save_api_address(selected_ip, &api_port);
});
ui.label(RichText::new(t!("network_settings.api_port"))
@ -144,16 +148,87 @@ impl NodeSetup {
// Show API port setup.
self.api_port_setup_ui(ui, cb);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.label(RichText::new(t!("network_settings.api_secret"))
.size(16.0)
.color(Colors::GRAY)
);
ui.add_space(6.0);
// Show API secret setup.
self.secret_ui(Self::API_SECRET_MODAL, ui, cb);
ui.add_space(6.0);
ui.label(RichText::new(t!("network_settings.foreign_api_secret"))
.size(16.0)
.color(Colors::GRAY)
);
ui.add_space(6.0);
// Show Foreign API secret setup.
self.secret_ui(Self::FOREIGN_API_SECRET_MODAL, ui, cb);
if Node::is_running() {
ui.add_space(2.0);
// Show reminder to restart node if settings are changed.
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::GREEN)
);
ui.add_space(2.0);
}
});
}
ui.add_space(6.0);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network_settings.ftl"))
.size(16.0)
.color(Colors::GRAY)
);
ui.add_space(6.0);
// Show FTL setup.
self.ftl_ui(ui, cb);
View::horizontal_line(ui, Colors::ITEM_STROKE);
ui.add_space(6.0);
});
}
/// Draw [`ChainTypes`] setup ui.
fn chain_type_ui(&mut self, ui: &mut egui::Ui) {
let saved_chain_type = AppConfig::chain_type();
let mut selected_chain_type = saved_chain_type;
ui.columns(2, |columns| {
columns[0].vertical_centered(|ui| {
let main_type = ChainTypes::Mainnet;
View::radio_value(ui, &mut selected_chain_type, main_type, "Mainnet".to_string());
});
columns[1].vertical_centered(|ui| {
let test_type = ChainTypes::Testnet;
View::radio_value(ui, &mut selected_chain_type, test_type, "Testnet".to_string());
})
});
ui.add_space(4.0);
if saved_chain_type != selected_chain_type {
AppConfig::change_chain_type(&selected_chain_type);
if Node::is_running() {
// Show modal to apply changes by node restart.
let port_modal = Modal::new(NetworkSettings::NODE_RESTART_REQUIRED_MODAL)
.position(ModalPosition::Center)
.title(t!("network.settings"));
Navigator::show_modal(port_modal);
}
}
}
/// 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.
let (_, port) = NodeConfig::get_api_address();
// Show button to enter API server port.
View::button(ui, port.clone(), Colors::BUTTON, || {
// Setup values for modal.
self.api_port_edit = port;
@ -162,7 +237,7 @@ impl NodeSetup {
// Show API port modal.
let port_modal = Modal::new(Self::API_PORT_MODAL)
.position(ModalPosition::CenterTop)
.title(t!("network_settings.change_port"));
.title(t!("network_settings.change_value"));
Navigator::show_modal(port_modal);
cb.show_keyboard();
});
@ -174,25 +249,19 @@ impl NodeSetup {
.size(16.0)
.color(Colors::RED));
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);
}
ui.add_space(6.0);
}
/// Draw API port [`Modal`] content ui.
pub fn api_port_modal_ui(&mut self,
ui: &mut egui::Ui,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
pub fn api_port_modal(&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)
ui.label(RichText::new(t!("network_settings.api_port"))
.size(18.0)
.color(Colors::GRAY));
ui.add_space(8.0);
@ -222,6 +291,23 @@ impl NodeSetup {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(6.0, 0.0);
// Save button callback.
let on_save = || {
// Check if port is available.
let (api_ip, _) = NodeConfig::get_api_address();
let available = NodeConfig::is_api_port_available(&api_ip, &self.api_port_edit);
self.api_port_available_edit = available;
if available {
// Save port at config if it's available.
NodeConfig::save_api_address(&api_ip, &self.api_port_edit);
self.is_api_port_available = true;
cb.hide_keyboard();
modal.close();
}
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
@ -230,31 +316,244 @@ impl NodeSetup {
});
});
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 = NodeConfig::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();
}
});
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
});
});
ui.add_space(6.0);
});
});
}
/// Draw API secret token setup ui.
fn secret_ui(&mut self, modal_id: &'static str, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
// Setup values for modal
let secret_value = match modal_id {
Self::API_SECRET_MODAL => NodeConfig::get_api_secret(),
_ => NodeConfig::get_foreign_api_secret()
};
let secret_text = if secret_value.is_some() {
format!("{}{}{}{}{}{}{}{}{}{}", ASTERISK, ASTERISK, ASTERISK, ASTERISK,
ASTERISK, ASTERISK, ASTERISK, ASTERISK, ASTERISK, ASTERISK)
} else {
t!("network_settings.disabled")
};
// Show button to open secret modal.
View::button(ui, secret_text, Colors::BUTTON, || {
// Setup values for modal.
match modal_id {
Self::API_SECRET_MODAL => {
self.api_secret_edit = secret_value.unwrap_or("".to_string());
},
_ => {
self.foreign_api_secret_edit = secret_value.unwrap_or("".to_string());
}
}
// Show secret edit modal.
let port_modal = Modal::new(modal_id)
.position(ModalPosition::CenterTop)
.title(t!("network_settings.change_value"));
Navigator::show_modal(port_modal);
cb.show_keyboard();
});
ui.add_space(6.0);
}
/// Draw API port [`Modal`] content ui.
pub fn secret_modal(&mut self, ui: &mut egui::Ui, modal: &Modal, cb: &dyn PlatformCallbacks) {
ui.add_space(6.0);
ui.vertical_centered(|ui| {
let description = match modal.id {
Self::API_SECRET_MODAL => t!("network_settings.api_secret"),
_ => t!("network_settings.foreign_api_secret")
};
ui.label(RichText::new(description)
.size(18.0)
.color(Colors::GRAY));
ui.add_space(8.0);
// let Self { api_secret_edit, foreign_api_secret_edit, .. } = self;
// Draw API port text edit.
let edit_text = match modal.id {
Self::API_SECRET_MODAL => &mut self.api_secret_edit,
_ => &mut self.foreign_api_secret_edit
};
let text_edit_resp = egui::TextEdit::singleline(edit_text)
.id(Id::from(modal.id))
.font(TextStyle::Heading)
.cursor_at_end(true)
.ui(ui);
text_edit_resp.request_focus();
if text_edit_resp.clicked() {
cb.show_keyboard();
}
ui.add_space(12.0);
// Show buttons to copy/paste text.
ui.scope(|ui| {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(12.0, 0.0);
ui.columns(2, |columns| {
// Setup spacing between buttons.
columns[0].with_layout(Layout::right_to_left(Align::TOP), |ui| {
let copy_text = format!("{} {}", COPY, t!("network_settings.copy"));
View::button(ui, copy_text, Colors::WHITE, || {
match modal.id {
Self::API_SECRET_MODAL => {
cb.copy_string_to_buffer(self.api_secret_edit.clone());
},
_ => {
cb.copy_string_to_buffer(self.foreign_api_secret_edit.clone());
}
};
});
});
columns[1].with_layout(Layout::left_to_right(Align::TOP), |ui| {
let copy_text = format!("{} {}", CLIPBOARD_TEXT, t!("network_settings.paste"));
View::button(ui, copy_text, Colors::WHITE, || {
let text = cb.get_string_from_buffer();
match modal.id {
Self::API_SECRET_MODAL => self.api_secret_edit = text,
_ => self.foreign_api_secret_edit = text
};
});
});
});
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);
// Save button callback.
let on_save = || {
match modal.id {
Self::API_SECRET_MODAL => {
let api_secret = &self.api_secret_edit.clone();
NodeConfig::save_api_secret(api_secret);
}
_ => {
let foreign_api_secret = &self.foreign_api_secret_edit.clone();
NodeConfig::save_foreign_api_secret(foreign_api_secret);
}
};
cb.hide_keyboard();
modal.close();
};
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, on_save);
});
});
ui.add_space(6.0);
});
});
}
/// Draw FTL setup ui.
fn ftl_ui(&mut self, ui: &mut egui::Ui, cb: &dyn PlatformCallbacks) {
let ftl = NodeConfig::get_ftl();
// Show button to enter FTL value.
View::button(ui, ftl.clone(), Colors::BUTTON, || {
// Setup values for modal.
self.ftl_edit = ftl;
// Show stratum port modal.
let ftl_modal = Modal::new(Self::FTL_MODAL)
.position(ModalPosition::CenterTop)
.title(t!("network_settings.change_value"));
Navigator::show_modal(ftl_modal);
cb.show_keyboard();
});
ui.add_space(6.0);
ui.label(RichText::new(t!("network_settings.ftl_description"))
.size(16.0)
.color(Colors::INACTIVE_TEXT)
);
if Node::is_running() {
ui.add_space(2.0);
// Show reminder to restart node if settings are changed.
ui.label(RichText::new(t!("network_settings.restart_node_required"))
.size(16.0)
.color(Colors::GREEN)
);
ui.add_space(2.0);
}
ui.add_space(6.0);
}
/// Draw FTL [`Modal`] content.
pub fn ftl_modal(&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.ftl"))
.size(18.0)
.color(Colors::GRAY));
ui.add_space(8.0);
// Draw stratum port text edit.
let text_edit_resp = egui::TextEdit::singleline(&mut self.ftl_edit)
.id(Id::from(modal.id))
.font(TextStyle::Heading)
.desired_width(34.0)
.cursor_at_end(true)
.ui(ui);
text_edit_resp.request_focus();
if text_edit_resp.clicked() {
cb.show_keyboard();
}
// Show error when specified value is not valid.
if self.ftl_edit.parse::<u64>().is_err() {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.not_valid_value"))
.size(18.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(8.0, 0.0);
// Save button callback
let on_save = || {
if let Ok(ftl) = self.ftl_edit.parse::<u64>() {
NodeConfig::save_ftl(ftl);
cb.hide_keyboard();
modal.close();
}
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
// Close modal.
cb.hide_keyboard();
modal.close();
});
});
columns[1].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
});
});
ui.add_space(6.0);
});
}
}

View file

@ -12,17 +12,14 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::net::IpAddr;
use std::str::FromStr;
use egui::{RichText, TextStyle, Widget};
use crate::gui::{Colors, Navigator};
use crate::gui::icons::WRENCH;
use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, ModalPosition, Network, View};
use crate::gui::views::{Modal, ModalPosition, View};
use crate::gui::views::network_settings::NetworkSettings;
use crate::node::NodeConfig;
use crate::Settings;
/// Stratum server setup ui section.
pub struct StratumServerSetup {
@ -37,7 +34,7 @@ pub struct StratumServerSetup {
impl Default for StratumServerSetup {
fn default() -> Self {
let (ip, port) = NodeConfig::get_stratum_address_port();
let (ip, port) = NodeConfig::get_stratum_address();
let is_port_available = NodeConfig::is_stratum_port_available(&ip, &port);
Self {
stratum_port_edit: port,
@ -57,9 +54,9 @@ impl StratumServerSetup {
ui.add_space(4.0);
// Show message when IP addresses are not available on the system.
let all_ips = Network::get_ip_list();
let all_ips = NetworkSettings::get_ip_addrs();
if all_ips.is_empty() {
Network::no_ip_address_ui(ui);
NetworkSettings::no_ip_address_ui(ui);
return;
}
@ -70,10 +67,10 @@ impl StratumServerSetup {
);
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| {
let (ip, port) = NodeConfig::get_stratum_address();
NetworkSettings::ip_addrs_ui(ui, &ip, &all_ips, |selected_ip| {
self.is_port_available = NodeConfig::is_stratum_port_available(selected_ip, &port);
NodeConfig::save_stratum_address_port(selected_ip, &port);
NodeConfig::save_stratum_address(selected_ip, &port);
});
ui.label(RichText::new(t!("network_settings.port"))
@ -91,17 +88,16 @@ impl StratumServerSetup {
/// 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.
let (_, port) = NodeConfig::get_stratum_address();
// Show button to enter 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"));
.title(t!("network_settings.change_value"));
Navigator::show_modal(port_modal);
cb.show_keyboard();
});
@ -123,8 +119,8 @@ impl StratumServerSetup {
cb: &dyn PlatformCallbacks) {
ui.add_space(6.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network_settings.enter_value"))
.size(16.0)
ui.label(RichText::new(t!("network_settings.stratum_port"))
.size(18.0)
.color(Colors::GRAY));
ui.add_space(8.0);
@ -143,7 +139,7 @@ impl StratumServerSetup {
if !self.stratum_port_available_edit {
ui.add_space(12.0);
ui.label(RichText::new(t!("network_settings.port_unavailable"))
.size(16.0)
.size(18.0)
.color(Colors::RED));
}
@ -154,6 +150,26 @@ impl StratumServerSetup {
// Setup spacing between buttons.
ui.spacing_mut().item_spacing = egui::Vec2::new(8.0, 0.0);
// Save button callback
let on_save = || {
// Check if port is available.
let (stratum_ip, _) = NodeConfig::get_stratum_address();
let available = NodeConfig::is_stratum_port_available(
&stratum_ip,
&self.stratum_port_edit
);
self.stratum_port_available_edit = available;
// Save port at config if it's available.
if available {
NodeConfig::save_stratum_address(&stratum_ip, &self.stratum_port_edit);
self.is_port_available = true;
cb.hide_keyboard();
modal.close();
}
};
ui.columns(2, |columns| {
columns[0].vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::WHITE, || {
@ -163,24 +179,7 @@ impl StratumServerSetup {
});
});
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 = NodeConfig::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(&ip, &self.stratum_port_edit);
self.is_port_available = true;
cb.hide_keyboard();
modal.close();
}
});
View::button(ui, t!("modal.save"), Colors::WHITE, on_save);
});
});
ui.add_space(6.0);

View file

@ -15,6 +15,7 @@
use std::fs::File;
use std::io::{BufRead, BufReader, Write};
use std::net::{IpAddr, Ipv4Addr, SocketAddrV4, TcpListener};
use std::path::PathBuf;
use std::str::FromStr;
use grin_config::{config, ConfigError, ConfigMembers, GlobalConfig};
@ -26,7 +27,7 @@ use grin_servers::common::types::ChainValidationMode;
use serde::{Deserialize, Serialize};
use crate::node::Node;
use crate::Settings;
use crate::{AppConfig, Settings};
/// Wrapped node config to be used by [`grin_servers::Server`].
#[derive(Serialize, Deserialize)]
@ -37,9 +38,6 @@ pub struct NodeConfig {
impl NodeConfig {
/// Initialize integrated node config.
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);
let config_members = Self::for_chain_type(chain_type);
Self {
members: config_members
@ -48,6 +46,11 @@ impl NodeConfig {
/// Initialize config with provided [`ChainTypes`].
pub fn for_chain_type(chain_type: &ChainTypes) -> ConfigMembers {
// Check secret files for current chain type.
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);
// Create config.
let path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type));
let parsed = Settings::read_from_file::<ConfigMembers>(path.clone());
if !path.exists() || parsed.is_err() {
@ -81,9 +84,7 @@ impl NodeConfig {
chain_type: &ChainTypes,
secret_file_name: &str,
) -> Result<(), ConfigError> {
let grin_path = Settings::get_working_path(Some(chain_type));
let mut api_secret_path = grin_path;
api_secret_path.push(secret_file_name);
let api_secret_path = Self::get_secret_path(chain_type, secret_file_name);
if !api_secret_path.exists() {
config::init_api_secret(&api_secret_path)
} else {
@ -91,8 +92,16 @@ impl NodeConfig {
}
}
/// Get path for secret file.
fn get_secret_path(chain_type: &ChainTypes, secret_file_name: &str) -> PathBuf {
let grin_path = Settings::get_working_path(Some(chain_type));
let mut api_secret_path = grin_path;
api_secret_path.push(secret_file_name);
api_secret_path
}
/// Check whether a port is available on the provided host.
pub fn is_port_available(host: &String, port: &String) -> bool {
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);
@ -102,7 +111,7 @@ impl NodeConfig {
}
/// Get stratum server IP address and port.
pub fn get_stratum_address_port() -> (String, String) {
pub fn get_stratum_address() -> (String, String) {
let r_config = Settings::node_config_to_read();
let saved_stratum_addr = r_config
.members
@ -118,7 +127,7 @@ impl NodeConfig {
}
/// Save stratum server IP address and port.
pub fn save_stratum_address_port(addr: &String, port: &String) {
pub fn save_stratum_address(addr: &String, port: &String) {
let addr_to_save = format!("{}:{}", addr, port);
let mut w_node_config = Settings::node_config_to_update();
w_node_config
@ -135,7 +144,7 @@ impl NodeConfig {
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();
let (api_ip, api_port) = Self::get_api_address();
return if &api_ip == ip {
&api_port != port
} else {
@ -180,7 +189,7 @@ impl NodeConfig {
}
/// Get API server IP address and port.
pub fn get_api_address_port() -> (String, String) {
pub fn get_api_address() -> (String, String) {
let r_config = Settings::node_config_to_read();
let saved_api_addr = r_config
.members
@ -192,7 +201,7 @@ impl NodeConfig {
}
/// Save API server IP address and port.
pub fn save_api_address_port(addr: &String, port: &String) {
pub fn save_api_address(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;
@ -219,72 +228,102 @@ impl NodeConfig {
}
/// Get API secret text.
pub fn get_api_secret() -> String {
pub fn get_api_secret() -> Option<String> {
let r_config = Settings::node_config_to_read();
let api_secret_path = r_config
.members
.server
.api_secret_path
.as_ref()
.unwrap();
let api_secret_file = File::open(api_secret_path).unwrap();
let buf_reader = BufReader::new(api_secret_file);
let mut lines_iter = buf_reader.lines();
let first_line = lines_iter.next().unwrap();
first_line.unwrap()
.clone();
return if let Some(secret_path) = api_secret_path {
let api_secret_file = File::open(secret_path).unwrap();
let buf_reader = BufReader::new(api_secret_file);
let mut lines_iter = buf_reader.lines();
let first_line = lines_iter.next().unwrap();
Some(first_line.unwrap())
} else {
None
}
}
/// Save API secret text.
pub fn save_api_secret(api_secret: &String) {
if api_secret.is_empty() {
return;
}
let r_config = Settings::node_config_to_read();
let api_secret_path = r_config
.members
.server
.api_secret_path
.as_ref()
.unwrap();
let mut api_secret_file = File::create(api_secret_path).unwrap();
api_secret_file.write_all(api_secret.as_bytes()).unwrap();
Self::save_secret(api_secret, API_SECRET_FILE_NAME);
}
/// Get Foreign API secret text.
pub fn get_foreign_api_secret() -> String {
pub fn get_foreign_api_secret() -> Option<String> {
let r_config = Settings::node_config_to_read();
let foreign_api_secret_path = r_config
let foreign_secret_path = r_config
.members
.server
.foreign_api_secret_path
.as_ref()
.unwrap();
let foreign_api_secret_file = File::open(foreign_api_secret_path).unwrap();
let buf_reader = BufReader::new(foreign_api_secret_file);
let mut lines_iter = buf_reader.lines();
let first_line = lines_iter.next().unwrap();
first_line.unwrap()
.clone();
return if let Some(secret_path) = foreign_secret_path {
let foreign_secret_file = File::open(secret_path).unwrap();
let buf_reader = BufReader::new(foreign_secret_file);
let mut lines_iter = buf_reader.lines();
let first_line = lines_iter.next().unwrap();
Some(first_line.unwrap())
} else {
None
}
}
/// Save Foreign API secret text.
/// Update Foreign API secret.
pub fn save_foreign_api_secret(api_secret: &String) {
if api_secret.is_empty() {
Self::save_secret(api_secret, FOREIGN_API_SECRET_FILE_NAME);
}
/// Save secret value into specified file.
fn save_secret(value: &String, file_name: &str) {
// Remove config value to remove authorization.
if value.is_empty() {
let mut w_config = Settings::node_config_to_update();
match file_name {
API_SECRET_FILE_NAME => w_config.members.server.api_secret_path = None,
_ => w_config.members.server.foreign_api_secret_path = None
}
w_config.save();
return;
}
let r_config = Settings::node_config_to_read();
let foreign_api_secret_path = r_config
.members
.server
.foreign_api_secret_path
.as_ref()
.unwrap();
let mut foreign_api_secret_file = File::create(foreign_api_secret_path).unwrap();
foreign_api_secret_file.write_all(api_secret.as_bytes()).unwrap();
let mut secret_enabled = true;
// Get path for specified secret file.
let secret_path = {
let r_config = Settings::node_config_to_read();
let path = match file_name {
API_SECRET_FILE_NAME => r_config.members.server.api_secret_path.clone(),
_ => r_config.members.server.foreign_api_secret_path.clone()
};
path.unwrap_or_else(|| {
secret_enabled = false;
let chain_type = AppConfig::chain_type();
let path = Self::get_secret_path(&chain_type, file_name);
path.to_str().unwrap().to_string()
})
};
// Update secret path at config if authorization was disabled before.
if !secret_enabled {
let mut w_config = Settings::node_config_to_update();
match file_name {
API_SECRET_FILE_NAME => w_config
.members
.server
.api_secret_path = Some(secret_path.clone()),
_ => w_config.members.server.foreign_api_secret_path = Some(secret_path.clone())
};
w_config.save();
}
// Write secret text into file.
let mut secret_file = File::create(secret_path).unwrap();
secret_file.write_all(value.as_bytes()).unwrap();
}
/// Get Future Time Limit.
pub fn get_ftl() -> u64 {
Settings::node_config_to_read().members.server.future_time_limit
pub fn get_ftl() -> String {
Settings::node_config_to_read().members.server.future_time_limit.to_string()
}
/// Save Future Time Limit.

View file

@ -64,21 +64,44 @@ 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 {
self.chain_type = *chain_type;
self.save();
// Load config for selected chain type.
Settings::node_config_to_update().members = NodeConfig::for_chain_type(chain_type);
}
}
/// Save app config to disk.
pub fn save(&self) {
Settings::write_to_file(self, Settings::get_config_path(APP_CONFIG_FILE_NAME, None));
}
/// Change chain type and load new [`NodeConfig`] accordingly.
pub fn change_chain_type(chain_type: &ChainTypes) {
let current_chain_type = Self::chain_type();
if current_chain_type != *chain_type {
let mut w_app_config = Settings::app_config_to_update();
w_app_config.chain_type = *chain_type;
w_app_config.save();
// Load config for selected chain type.
let mut w_node_config = Settings::node_config_to_update();
w_node_config.members = NodeConfig::for_chain_type(chain_type);
w_node_config.save();
}
}
/// Get current [`ChainTypes`] for node and wallets.
pub fn chain_type() -> ChainTypes {
let r_config = Settings::app_config_to_read();
r_config.chain_type
}
/// Check if integrated node is starting with application.
pub fn autostart_node() -> bool {
let r_config = Settings::app_config_to_read();
r_config.auto_start_node
}
/// Toggle integrated node autostart.
pub fn toggle_node_autostart() {
let autostart = Self::autostart_node();
let mut w_app_config = Settings::app_config_to_update();
w_app_config.auto_start_node = !autostart;
w_app_config.save();
}
}
const WORKING_DIRECTORY_NAME: &'static str = ".grim";
@ -150,7 +173,7 @@ impl Settings {
let file_content = fs::read_to_string(config_path.clone())?;
let parsed = toml::from_str::<T>(file_content.as_str());
match parsed {
Ok(cfg) => { Ok(cfg) }
Ok(cfg) => Ok(cfg),
Err(e) => {
return Err(ConfigError::ParseError(
config_path.to_str().unwrap().to_string(),