config: add application settings config, refactor node server config
This commit is contained in:
parent
117f450574
commit
ba4c1da1f4
8 changed files with 315 additions and 63 deletions
34
Cargo.lock
generated
34
Cargo.lock
generated
|
@ -521,7 +521,7 @@ checksum = "031718ddb8f78aa5def78a09e90defe30151d1f6c672f937af4dd916429ed996"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"semver",
|
"semver",
|
||||||
"serde",
|
"serde",
|
||||||
"toml",
|
"toml 0.5.11",
|
||||||
"url",
|
"url",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1718,7 +1718,9 @@ dependencies = [
|
||||||
"openssl-sys",
|
"openssl-sys",
|
||||||
"pollster 0.3.0",
|
"pollster 0.3.0",
|
||||||
"rust-i18n",
|
"rust-i18n",
|
||||||
|
"serde",
|
||||||
"sys-locale",
|
"sys-locale",
|
||||||
|
"toml 0.7.4",
|
||||||
"wgpu",
|
"wgpu",
|
||||||
"winit",
|
"winit",
|
||||||
]
|
]
|
||||||
|
@ -1791,7 +1793,7 @@ dependencies = [
|
||||||
"rand 0.6.5",
|
"rand 0.6.5",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"toml",
|
"toml 0.5.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3541,7 +3543,7 @@ dependencies = [
|
||||||
"rust-i18n-macro",
|
"rust-i18n-macro",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
"toml",
|
"toml 0.5.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -3790,6 +3792,15 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_spanned"
|
||||||
|
version = "0.6.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_yaml"
|
name = "serde_yaml"
|
||||||
version = "0.8.26"
|
version = "0.8.26"
|
||||||
|
@ -4234,11 +4245,26 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "toml"
|
||||||
|
version = "0.7.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
|
"toml_datetime",
|
||||||
|
"toml_edit",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_datetime"
|
name = "toml_datetime"
|
||||||
version = "0.6.2"
|
version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
|
checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toml_edit"
|
name = "toml_edit"
|
||||||
|
@ -4247,6 +4273,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
|
checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"serde",
|
||||||
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
"winnow",
|
"winnow",
|
||||||
]
|
]
|
||||||
|
|
|
@ -47,6 +47,8 @@ rust-i18n = "1.1.4"
|
||||||
sys-locale = "0.3.0"
|
sys-locale = "0.3.0"
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
|
toml = "0.7.4"
|
||||||
|
serde = "1.0.164"
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
winit = { git = "https://github.com/rib/winit", branch = "android-activity" }
|
winit = { git = "https://github.com/rib/winit", branch = "android-activity" }
|
||||||
|
|
15
src/grim.rs
15
src/grim.rs
|
@ -13,13 +13,12 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use eframe::{AppCreator, NativeOptions, Renderer, Theme};
|
use eframe::{AppCreator, NativeOptions, Renderer, Theme};
|
||||||
use grin_core::global::ChainTypes;
|
|
||||||
use log::LevelFilter::Info;
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
use winit::platform::android::activity::AndroidApp;
|
use winit::platform::android::activity::AndroidApp;
|
||||||
|
|
||||||
use crate::gui::{App, PlatformApp};
|
use crate::gui::{App, PlatformApp};
|
||||||
use crate::node::Node;
|
use crate::node::Node;
|
||||||
|
use crate::Settings;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
|
@ -28,9 +27,10 @@ fn android_main(app: AndroidApp) {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
std::env::set_var("RUST_BACKTRACE", "full");
|
std::env::set_var("RUST_BACKTRACE", "full");
|
||||||
android_logger::init_once(
|
let log_config = android_logger::Config::default()
|
||||||
android_logger::Config::default().with_max_level(Info).with_tag("grim"),
|
.with_max_level(log::LevelFilter::Info)
|
||||||
);
|
.with_tag("grim");
|
||||||
|
android_logger::init_once(log_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
use crate::gui::platform::Android;
|
use crate::gui::platform::Android;
|
||||||
|
@ -73,7 +73,10 @@ fn start(mut options: NativeOptions, app_creator: AppCreator) {
|
||||||
options.renderer = Renderer::Wgpu;
|
options.renderer = Renderer::Wgpu;
|
||||||
|
|
||||||
setup_i18n();
|
setup_i18n();
|
||||||
Node::start(ChainTypes::Mainnet);
|
|
||||||
|
if Settings::get_app_config().auto_start_node {
|
||||||
|
Node::start();
|
||||||
|
}
|
||||||
|
|
||||||
eframe::run_native("Grim", options, app_creator);
|
eframe::run_native("Grim", options, app_creator);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,3 +21,6 @@ mod wallet;
|
||||||
mod gui;
|
mod gui;
|
||||||
|
|
||||||
pub mod grim;
|
pub mod grim;
|
||||||
|
|
||||||
|
mod settings;
|
||||||
|
pub use settings::{Settings, AppConfig};
|
102
src/node/config.rs
Normal file
102
src/node/config.rs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
// Copyright 2023 The Grim Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::{fs, thread};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
|
|
||||||
|
use grin_config::{config, ConfigError, ConfigMembers, GlobalConfig};
|
||||||
|
use grin_config::config::{API_SECRET_FILE_NAME, FOREIGN_API_SECRET_FILE_NAME, SERVER_CONFIG_FILE_NAME};
|
||||||
|
use grin_core::global::ChainTypes;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::Settings;
|
||||||
|
|
||||||
|
/// Node config that contains [`GlobalConfig`] to be used by [`grin_servers::Server`].
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct NodeConfig {
|
||||||
|
pub global_config: GlobalConfig,
|
||||||
|
update_needed: AtomicBool,
|
||||||
|
updating: AtomicBool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NodeConfig {
|
||||||
|
/// Initialize node config with provided chain type from the disk.
|
||||||
|
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_path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type));
|
||||||
|
|
||||||
|
// Create default config if it doesn't exist or has wrong format.
|
||||||
|
if !config_path.exists() || toml::from_str::<ConfigMembers>(
|
||||||
|
fs::read_to_string(config_path.clone()).unwrap().as_str()
|
||||||
|
).is_err() {
|
||||||
|
let mut default_config = GlobalConfig::for_chain(chain_type);
|
||||||
|
default_config.update_paths(&Settings::get_working_path(Some(chain_type)));
|
||||||
|
let _ = default_config.write_to_file(config_path.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
let config = GlobalConfig::new(config_path.to_str().unwrap());
|
||||||
|
|
||||||
|
Self {
|
||||||
|
global_config: config.unwrap(),
|
||||||
|
update_needed: AtomicBool::new(false),
|
||||||
|
updating: AtomicBool::new(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write node config on disk.
|
||||||
|
pub fn save_config(&self) {
|
||||||
|
if self.updating.load(Ordering::Relaxed) {
|
||||||
|
self.update_needed.store(true, Ordering::Relaxed);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread::spawn(move || loop {
|
||||||
|
let config = Settings::get_node_config();
|
||||||
|
config.update_needed.store(false, Ordering::Relaxed);
|
||||||
|
config.updating.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
|
let chain_type = &config.global_config.members.clone().unwrap().server.chain_type;
|
||||||
|
let config_path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, Some(chain_type));
|
||||||
|
|
||||||
|
// Write config to file.
|
||||||
|
let conf_out = toml::to_string(&config.global_config.members).unwrap();
|
||||||
|
let mut file = File::create(config_path.to_str().unwrap()).unwrap();
|
||||||
|
file.write_all(conf_out.as_bytes()).unwrap();
|
||||||
|
|
||||||
|
if !config.update_needed.load(Ordering::Relaxed) {
|
||||||
|
config.updating.store(false, Ordering::Relaxed);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check that the api secret files exist and are valid.
|
||||||
|
fn check_api_secret_files(
|
||||||
|
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);
|
||||||
|
if !api_secret_path.exists() {
|
||||||
|
config::init_api_secret(&api_secret_path)
|
||||||
|
} else {
|
||||||
|
config::check_api_secret(&api_secret_path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,5 +13,7 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
mod node;
|
mod node;
|
||||||
|
|
||||||
pub use node::Node;
|
pub use node::Node;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
pub use config::NodeConfig;
|
|
@ -16,12 +16,10 @@ use std::{fs, thread};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::thread::JoinHandle;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use futures::channel::oneshot;
|
use futures::channel::oneshot;
|
||||||
use grin_chain::SyncStatus;
|
use grin_chain::SyncStatus;
|
||||||
use grin_config::config;
|
|
||||||
use grin_core::global;
|
use grin_core::global;
|
||||||
use grin_core::global::ChainTypes;
|
use grin_core::global::ChainTypes;
|
||||||
use grin_servers::{Server, ServerStats};
|
use grin_servers::{Server, ServerStats};
|
||||||
|
@ -29,6 +27,8 @@ use jni::sys::{jboolean, jstring};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use log::info;
|
use log::info;
|
||||||
|
|
||||||
|
use crate::Settings;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
/// Static thread-aware state of [`Node`] to be updated from another thread.
|
/// Static thread-aware state of [`Node`] to be updated from another thread.
|
||||||
static ref NODE_STATE: Arc<Node> = Arc::new(Node::default());
|
static ref NODE_STATE: Arc<Node> = Arc::new(Node::default());
|
||||||
|
@ -38,8 +38,6 @@ lazy_static! {
|
||||||
pub struct Node {
|
pub struct Node {
|
||||||
/// Statistics data for UI.
|
/// Statistics data for UI.
|
||||||
stats: Arc<RwLock<Option<ServerStats>>>,
|
stats: Arc<RwLock<Option<ServerStats>>>,
|
||||||
/// Chain type of launched server.
|
|
||||||
chain_type: Arc<RwLock<ChainTypes>>,
|
|
||||||
/// Indicator if server is starting.
|
/// Indicator if server is starting.
|
||||||
starting: AtomicBool,
|
starting: AtomicBool,
|
||||||
/// Thread flag to stop the server and start it again.
|
/// Thread flag to stop the server and start it again.
|
||||||
|
@ -54,7 +52,6 @@ impl Default for Node {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
stats: Arc::new(RwLock::new(None)),
|
stats: Arc::new(RwLock::new(None)),
|
||||||
chain_type: Arc::new(RwLock::new(ChainTypes::Mainnet)),
|
|
||||||
starting: AtomicBool::new(false),
|
starting: AtomicBool::new(false),
|
||||||
restart_needed: AtomicBool::new(false),
|
restart_needed: AtomicBool::new(false),
|
||||||
stop_needed: AtomicBool::new(false),
|
stop_needed: AtomicBool::new(false),
|
||||||
|
@ -70,52 +67,48 @@ impl Node {
|
||||||
NODE_STATE.exit_after_stop.store(exit_after_stop, Ordering::Relaxed);
|
NODE_STATE.exit_after_stop.store(exit_after_stop, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start [`Server`] with provided chain type.
|
/// Start the node.
|
||||||
pub fn start(chain_type: ChainTypes) {
|
pub fn start() {
|
||||||
if !Self::is_running() {
|
if !Self::is_running() {
|
||||||
let mut w_chain_type = NODE_STATE.chain_type.write().unwrap();
|
|
||||||
*w_chain_type = chain_type;
|
|
||||||
Self::start_server_thread();
|
Self::start_server_thread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Restart [`Server`] with provided chain type.
|
/// Restart the node.
|
||||||
pub fn restart(chain_type: ChainTypes) {
|
pub fn restart() {
|
||||||
if Self::is_running() {
|
if Self::is_running() {
|
||||||
let mut w_chain_type = NODE_STATE.chain_type.write().unwrap();
|
|
||||||
*w_chain_type = chain_type;
|
|
||||||
NODE_STATE.restart_needed.store(true, Ordering::Relaxed);
|
NODE_STATE.restart_needed.store(true, Ordering::Relaxed);
|
||||||
} else {
|
} else {
|
||||||
Node::start(chain_type);
|
Node::start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [`Server`] is starting.
|
/// Check if node is starting.
|
||||||
pub fn is_starting() -> bool {
|
pub fn is_starting() -> bool {
|
||||||
NODE_STATE.starting.load(Ordering::Relaxed)
|
NODE_STATE.starting.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [`Server`] is running.
|
/// Check if node is running.
|
||||||
pub fn is_running() -> bool {
|
pub fn is_running() -> bool {
|
||||||
Self::get_sync_status().is_some()
|
Self::get_sync_status().is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [`Server`] is stopping.
|
/// Check if node is stopping.
|
||||||
pub fn is_stopping() -> bool {
|
pub fn is_stopping() -> bool {
|
||||||
NODE_STATE.stop_needed.load(Ordering::Relaxed)
|
NODE_STATE.stop_needed.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if [`Server`] is restarting.
|
/// Check if node is restarting.
|
||||||
pub fn is_restarting() -> bool {
|
pub fn is_restarting() -> bool {
|
||||||
NODE_STATE.restart_needed.load(Ordering::Relaxed)
|
NODE_STATE.restart_needed.load(Ordering::Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get [`Server`] statistics.
|
/// Get node [`Server`] statistics.
|
||||||
pub fn get_stats() -> RwLockReadGuard<'static, Option<ServerStats>> {
|
pub fn get_stats() -> RwLockReadGuard<'static, Option<ServerStats>> {
|
||||||
NODE_STATE.stats.read().unwrap()
|
NODE_STATE.stats.read().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get [`Server`] synchronization status, empty when Server is not running.
|
/// Get synchronization status, empty when [`Server`] is not running.
|
||||||
pub fn get_sync_status() -> Option<SyncStatus> {
|
pub fn get_sync_status() -> Option<SyncStatus> {
|
||||||
// Return Shutdown status when node is stopping.
|
// Return Shutdown status when node is stopping.
|
||||||
if Self::is_stopping() {
|
if Self::is_stopping() {
|
||||||
|
@ -135,13 +128,13 @@ impl Node {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a thread to launch [`Server`] and update [`NODE_STATE`] with server statistics.
|
/// Start the node [`Server`] at separate thread to update [`NODE_STATE`] with [`ServerStats`].
|
||||||
fn start_server_thread() {
|
fn start_server_thread() {
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
NODE_STATE.starting.store(true, Ordering::Relaxed);
|
NODE_STATE.starting.store(true, Ordering::Relaxed);
|
||||||
|
|
||||||
// Start the server.
|
// Start the server.
|
||||||
let mut server = start_server(&NODE_STATE.chain_type.read().unwrap());
|
let mut server = start_server();
|
||||||
let mut first_start = true;
|
let mut first_start = true;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -155,8 +148,8 @@ impl Node {
|
||||||
// Stop the server.
|
// Stop the server.
|
||||||
server.stop();
|
server.stop();
|
||||||
|
|
||||||
// Create new server with current chain type.
|
// Create new server.
|
||||||
server = start_server(&NODE_STATE.chain_type.read().unwrap());
|
server = start_server();
|
||||||
|
|
||||||
NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
|
NODE_STATE.restart_needed.store(false, Ordering::Relaxed);
|
||||||
} else if Self::is_stopping() {
|
} else if Self::is_stopping() {
|
||||||
|
@ -310,27 +303,12 @@ impl Node {
|
||||||
SyncStatus::Shutdown => t!("sync_status.shutdown"),
|
SyncStatus::Shutdown => t!("sync_status.shutdown"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the [`Server`] with provided chain type.
|
/// Start the node [`Server`].
|
||||||
fn start_server(chain_type: &ChainTypes) -> Server {
|
fn start_server() -> Server {
|
||||||
// Initialize config
|
// Get current global config
|
||||||
let mut node_config_result = config::initial_setup_server(chain_type);
|
let config = &Settings::get_node_config().global_config;
|
||||||
if node_config_result.is_err() {
|
|
||||||
// Remove config file on init error
|
|
||||||
let mut grin_path = dirs::home_dir().unwrap();
|
|
||||||
grin_path.push(".grin");
|
|
||||||
grin_path.push(chain_type.shortname());
|
|
||||||
grin_path.push(config::SERVER_CONFIG_FILE_NAME);
|
|
||||||
fs::remove_file(grin_path).unwrap();
|
|
||||||
|
|
||||||
// Reinit config
|
|
||||||
node_config_result = config::initial_setup_server(chain_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
let node_config = node_config_result.ok();
|
|
||||||
let config = node_config.clone().unwrap();
|
|
||||||
let server_config = config.members.as_ref().unwrap().server.clone();
|
let server_config = config.members.as_ref().unwrap().server.clone();
|
||||||
|
|
||||||
// Remove temporary file dir
|
// Remove temporary file dir
|
||||||
|
@ -367,24 +345,19 @@ fn start_server(chain_type: &ChainTypes) -> Server {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !global::GLOBAL_ACCEPT_FEE_BASE.is_init() {
|
if !global::GLOBAL_ACCEPT_FEE_BASE.is_init() {
|
||||||
let afb = config
|
let afb = config.members.as_ref().unwrap().server.pool_config.accept_fee_base;
|
||||||
.members
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.server
|
|
||||||
.pool_config
|
|
||||||
.accept_fee_base;
|
|
||||||
global::init_global_accept_fee_base(afb);
|
global::init_global_accept_fee_base(afb);
|
||||||
info!("Accept Fee Base: {:?}", global::get_accept_fee_base());
|
info!("Accept Fee Base: {:?}", global::get_accept_fee_base());
|
||||||
}
|
}
|
||||||
if !global::GLOBAL_FUTURE_TIME_LIMIT.is_init() {
|
if !global::GLOBAL_FUTURE_TIME_LIMIT.is_init() {
|
||||||
global::init_global_future_time_limit(config.members.unwrap().server.future_time_limit);
|
let future_time_limit = config.members.as_ref().unwrap().server.future_time_limit;
|
||||||
|
global::init_global_future_time_limit(future_time_limit);
|
||||||
info!("Future Time Limit: {:?}", global::get_future_time_limit());
|
info!("Future Time Limit: {:?}", global::get_future_time_limit());
|
||||||
}
|
}
|
||||||
|
|
||||||
let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) =
|
let api_chan: &'static mut (oneshot::Sender<()>, oneshot::Receiver<()>) =
|
||||||
Box::leak(Box::new(oneshot::channel::<()>()));
|
Box::leak(Box::new(oneshot::channel::<()>()));
|
||||||
let mut server_result = Server::new(server_config.clone(), None, api_chan);
|
let server_result = Server::new(server_config, None, api_chan);
|
||||||
//TODO: handle server errors
|
//TODO: handle server errors
|
||||||
//
|
//
|
||||||
// if server_result.is_err() {
|
// if server_result.is_err() {
|
||||||
|
|
139
src/settings.rs
Normal file
139
src/settings.rs
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright 2023 The Grim Developers
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::fs::{self, File};
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{Arc, RwLock, RwLockReadGuard};
|
||||||
|
|
||||||
|
use grin_config::ConfigError;
|
||||||
|
use grin_core::global::ChainTypes;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use serde::de::DeserializeOwned;
|
||||||
|
|
||||||
|
use crate::node::NodeConfig;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// Static settings state to be accessible globally.
|
||||||
|
static ref SETTINGS_STATE: Arc<Settings> = Arc::new(Settings::init());
|
||||||
|
}
|
||||||
|
|
||||||
|
const APP_CONFIG_FILE_NAME: &'static str = "app.toml";
|
||||||
|
|
||||||
|
/// Application settings config.
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
pub struct AppConfig {
|
||||||
|
/// Run node server on startup.
|
||||||
|
pub auto_start_node: bool,
|
||||||
|
/// Chain type for node server.
|
||||||
|
pub chain_type: ChainTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for AppConfig {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
auto_start_node: false,
|
||||||
|
chain_type: ChainTypes::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AppConfig {
|
||||||
|
/// Initialize application config from the disk.
|
||||||
|
pub fn init() -> Self {
|
||||||
|
let config_path = Settings::get_config_path(APP_CONFIG_FILE_NAME, None);
|
||||||
|
let parsed = Settings::read_from_file::<AppConfig>(config_path.clone());
|
||||||
|
if !config_path.exists() || parsed.is_err() {
|
||||||
|
let default_config = AppConfig::default();
|
||||||
|
Settings::write_to_file(&default_config, config_path.to_str().unwrap());
|
||||||
|
default_config
|
||||||
|
} else {
|
||||||
|
parsed.unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Settings {
|
||||||
|
app_config: Arc<RwLock<AppConfig>>,
|
||||||
|
node_config: Arc<RwLock<NodeConfig>>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Settings {
|
||||||
|
/// Initialize settings with app and node configs from the disk.
|
||||||
|
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)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_node_config() -> RwLockReadGuard<'static, NodeConfig> {
|
||||||
|
SETTINGS_STATE.node_config.read().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_app_config() -> RwLockReadGuard<'static, AppConfig> {
|
||||||
|
SETTINGS_STATE.app_config.read().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get working directory path for application.
|
||||||
|
pub fn get_working_path(chain_type: Option<&ChainTypes>) -> PathBuf {
|
||||||
|
// Check if dir exists
|
||||||
|
let mut path = match dirs::home_dir() {
|
||||||
|
Some(p) => p,
|
||||||
|
None => PathBuf::new(),
|
||||||
|
};
|
||||||
|
path.push(".grim");
|
||||||
|
if chain_type.is_some() {
|
||||||
|
path.push(chain_type.unwrap().shortname());
|
||||||
|
}
|
||||||
|
// Create if the default path doesn't exist
|
||||||
|
if !path.exists() {
|
||||||
|
let _ = fs::create_dir_all(path.clone());
|
||||||
|
}
|
||||||
|
path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get config file path from provided name and [`ChainTypes`] if needed.
|
||||||
|
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);
|
||||||
|
settings_path
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read config from file
|
||||||
|
pub fn read_from_file<T: DeserializeOwned>(config_path: PathBuf) -> Result<T, ConfigError> {
|
||||||
|
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) }
|
||||||
|
Err(e) => {
|
||||||
|
return Err(ConfigError::ParseError(
|
||||||
|
config_path.to_str().unwrap().to_string(),
|
||||||
|
format!("{}", e),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write config to a file
|
||||||
|
pub fn write_to_file<T: Serialize>(config: &T, name: &str) {
|
||||||
|
let conf_out = toml::to_string(config).unwrap();
|
||||||
|
let mut file = File::create(name).unwrap();
|
||||||
|
file.write_all(conf_out.as_bytes()).unwrap();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue