feat: crash report

This commit is contained in:
ardocrat 2024-08-07 19:14:11 +03:00
parent 92eb5f59ad
commit f3db1005b5
15 changed files with 182 additions and 68 deletions

8
Cargo.lock generated
View file

@ -3803,6 +3803,7 @@ dependencies = [
"arboard", "arboard",
"arti-client", "arti-client",
"arti-hyper", "arti-hyper",
"backtrace",
"chrono", "chrono",
"curve25519-dalek 4.1.3", "curve25519-dalek 4.1.3",
"dark-light", "dark-light",
@ -3839,6 +3840,7 @@ dependencies = [
"nokhwa", "nokhwa",
"openpnp_capture_sys", "openpnp_capture_sys",
"openssl-sys", "openssl-sys",
"panic-message",
"parking_lot 0.12.3", "parking_lot 0.12.3",
"qrcode", "qrcode",
"qrcodegen", "qrcodegen",
@ -6563,6 +6565,12 @@ dependencies = [
"sha2 0.10.8", "sha2 0.10.8",
] ]
[[package]]
name = "panic-message"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384e52fd8fbd4cbe3c317e8216260c21a0f9134de108cea8a4dd4e7e152c472d"
[[package]] [[package]]
name = "parking" name = "parking"
version = "2.2.0" version = "2.2.0"

View file

@ -16,6 +16,9 @@ path = "src/main.rs"
name="grim" name="grim"
crate-type = ["rlib"] crate-type = ["rlib"]
[profile.release]
debug = 1
[profile.release-apk] [profile.release-apk]
inherits = "release" inherits = "release"
strip = true strip = true
@ -51,6 +54,8 @@ egui_extras = { version = "0.28.1", features = ["image", "svg"] }
rust-i18n = "2.3.1" rust-i18n = "2.3.1"
## other ## other
backtrace = "0.3"
panic-message = "0.3.0"
thiserror = "1.0.58" thiserror = "1.0.58"
futures = "0.3" futures = "0.3"
dirs = "5.0.1" dirs = "5.0.1"

View file

@ -26,6 +26,8 @@ theme: 'Theme:'
dark: Dunkel dark: Dunkel
light: Hell light: Hell
choose_file: Datei auswählen choose_file: Datei auswählen
crash_report: Absturzbericht
crash_report_warning: Anwendung wurde beim letzten Mal unerwartet geschlossen, Sie können den Absturzbericht mit Entwicklern teilen.
wallets: wallets:
await_conf_amount: Erwarte Bestätigung await_conf_amount: Erwarte Bestätigung
await_fin_amount: Warten auf die Fertigstellung await_fin_amount: Warten auf die Fertigstellung

View file

@ -26,6 +26,8 @@ theme: 'Theme:'
dark: Dark dark: Dark
light: Light light: Light
choose_file: Choose file choose_file: Choose file
crash_report: Crash report
crash_report_warning: Application closed unexpectedly last time, you can share crash report with developers.
wallets: wallets:
await_conf_amount: Awaiting confirmation await_conf_amount: Awaiting confirmation
await_fin_amount: Awaiting finalization await_fin_amount: Awaiting finalization

View file

@ -26,6 +26,8 @@ theme: 'Thème:'
dark: Sombre dark: Sombre
light: Clair light: Clair
choose_file: Choisir un fichier choose_file: Choisir un fichier
crash_report: Rapport d'échec
crash_report_warning: L'application s'est fermée de manière inattendue la dernière fois, vous pouvez partager un rapport d'incident avec les développeurs.
wallets: wallets:
await_conf_amount: En attente de confirmation await_conf_amount: En attente de confirmation
await_fin_amount: En attente de finalisation await_fin_amount: En attente de finalisation

View file

@ -26,6 +26,8 @@ theme: 'Тема:'
dark: Тёмная dark: Тёмная
light: Светлая light: Светлая
choose_file: Выбрать файл choose_file: Выбрать файл
crash_report: Отчёт о сбое
crash_report_warning: В прошлый раз приложение неожиданно закрылось, вы можете поделиться отчетом о сбое с разработчиками.
wallets: wallets:
await_conf_amount: Ожидает подтверждения await_conf_amount: Ожидает подтверждения
await_fin_amount: Ожидает завершения await_fin_amount: Ожидает завершения

View file

@ -26,6 +26,8 @@ theme: 'Tema:'
dark: Karanlik dark: Karanlik
light: Isik light: Isik
choose_file: Dosya seçin choose_file: Dosya seçin
crash_report: Ariza Raporu
crash_report_warning: Uygulama beklenmedik bir sekilde kapandi son kez, kilitlenme raporunu gelistiricilerle paylasabilirsiniz.
wallets: wallets:
await_conf_amount: Onay bekleniyor await_conf_amount: Onay bekleniyor
await_fin_amount: Tamamlanma bekleniyor await_fin_amount: Tamamlanma bekleniyor

View file

@ -12,6 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::fs;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use egui::os::OperatingSystem; use egui::os::OperatingSystem;
use egui::{Align, Layout, RichText}; use egui::{Align, Layout, RichText};
@ -20,10 +21,10 @@ use lazy_static::lazy_static;
use crate::gui::Colors; use crate::gui::Colors;
use crate::gui::platform::PlatformCallbacks; use crate::gui::platform::PlatformCallbacks;
use crate::gui::views::{Modal, View}; use crate::gui::views::{Modal, View};
use crate::gui::views::types::ModalContainer; use crate::gui::views::types::{ModalContainer, ModalPosition};
use crate::node::Node; use crate::node::Node;
use crate::AppConfig; use crate::{AppConfig, Settings};
use crate::gui::icons::{CHECK, CHECK_FAT}; use crate::gui::icons::{CHECK, CHECK_FAT, FILE_X};
use crate::gui::views::network::{NetworkContent, NodeSetup}; use crate::gui::views::network::{NetworkContent, NodeSetup};
use crate::gui::views::wallets::WalletsContent; use crate::gui::views::wallets::WalletsContent;
@ -63,9 +64,10 @@ impl Default for Content {
show_exit_progress: false, show_exit_progress: false,
first_draw: true, first_draw: true,
allowed_modal_ids: vec![ allowed_modal_ids: vec![
Self::EXIT_MODAL_ID, Self::EXIT_CONFIRMATION_MODAL,
Self::SETTINGS_MODAL, Self::SETTINGS_MODAL,
Self::ANDROID_INTEGRATED_NODE_WARNING_MODAL, Self::ANDROID_INTEGRATED_NODE_WARNING_MODAL,
Self::CRASH_REPORT_MODAL
], ],
} }
} }
@ -79,11 +81,12 @@ impl ModalContainer for Content {
fn modal_ui(&mut self, fn modal_ui(&mut self,
ui: &mut egui::Ui, ui: &mut egui::Ui,
modal: &Modal, modal: &Modal,
_: &dyn PlatformCallbacks) { cb: &dyn PlatformCallbacks) {
match modal.id { match modal.id {
Self::EXIT_MODAL_ID => self.exit_modal_content(ui, modal), Self::EXIT_CONFIRMATION_MODAL => self.exit_modal_content(ui, modal),
Self::SETTINGS_MODAL => self.settings_modal_ui(ui, modal), Self::SETTINGS_MODAL => self.settings_modal_ui(ui, modal),
Self::ANDROID_INTEGRATED_NODE_WARNING_MODAL => self.android_warning_modal_ui(ui, modal), Self::ANDROID_INTEGRATED_NODE_WARNING_MODAL => self.android_warning_modal_ui(ui, modal),
Self::CRASH_REPORT_MODAL => self.crash_report_modal_ui(ui, modal, cb),
_ => {} _ => {}
} }
} }
@ -91,12 +94,13 @@ impl ModalContainer for Content {
impl Content { impl Content {
/// Identifier for exit confirmation [`Modal`]. /// Identifier for exit confirmation [`Modal`].
pub const EXIT_MODAL_ID: &'static str = "exit_confirmation_modal"; pub const EXIT_CONFIRMATION_MODAL: &'static str = "exit_confirmation_modal";
/// Identifier for wallet opening [`Modal`]. /// Identifier for wallet opening [`Modal`].
pub const SETTINGS_MODAL: &'static str = "settings_modal"; pub const SETTINGS_MODAL: &'static str = "settings_modal";
/// Identifier for integrated node warning [`Modal`] on Android. /// Identifier for integrated node warning [`Modal`] on Android.
const ANDROID_INTEGRATED_NODE_WARNING_MODAL: &'static str = "android_node_warning_modal"; const ANDROID_INTEGRATED_NODE_WARNING_MODAL: &'static str = "android_node_warning_modal";
/// Identifier for crash report [`Modal`].
const CRASH_REPORT_MODAL: &'static str = "crash_report_modal";
/// Default width of side panel at application UI. /// Default width of side panel at application UI.
pub const SIDE_PANEL_WIDTH: f32 = 400.0; pub const SIDE_PANEL_WIDTH: f32 = 400.0;
@ -132,16 +136,23 @@ impl Content {
self.wallets.ui(ui, cb); self.wallets.ui(ui, cb);
}); });
if self.first_draw {
// Show crash report if needed.
if AppConfig::show_crash() {
Modal::new(Self::CRASH_REPORT_MODAL)
.closeable(false)
.position(ModalPosition::Center)
.title(t!("crash_report"))
.show();
} else {
// Show integrated node warning on Android if needed. // Show integrated node warning on Android if needed.
if self.first_draw && OperatingSystem::from_target_os() == OperatingSystem::Android && if OperatingSystem::from_target_os() == OperatingSystem::Android &&
AppConfig::android_integrated_node_warning_needed() { AppConfig::android_integrated_node_warning_needed() {
Modal::new(Self::ANDROID_INTEGRATED_NODE_WARNING_MODAL) Modal::new(Self::ANDROID_INTEGRATED_NODE_WARNING_MODAL)
.title(t!("network.node")) .title(t!("network.node"))
.show(); .show();
} }
}
// Setup first draw flag.
if self.first_draw {
self.first_draw = false; self.first_draw = false;
} }
} }
@ -187,9 +198,9 @@ impl Content {
NETWORK_PANEL_OPEN.load(Ordering::Relaxed) NETWORK_PANEL_OPEN.load(Ordering::Relaxed)
} }
/// Show exit confirmation modal. /// Show exit confirmation [`Modal`].
pub fn show_exit_modal() { pub fn show_exit_modal() {
Modal::new(Self::EXIT_MODAL_ID) Modal::new(Self::EXIT_CONFIRMATION_MODAL)
.title(t!("modal.confirmation")) .title(t!("modal.confirmation"))
.show(); .show();
} }
@ -383,7 +394,7 @@ impl Content {
ui.add_space(6.0); ui.add_space(6.0);
ui.vertical_centered(|ui| { ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("network.android_warning")) ui.label(RichText::new(t!("network.android_warning"))
.size(15.0) .size(16.0)
.color(Colors::text(false))); .color(Colors::text(false)));
}); });
ui.add_space(8.0); ui.add_space(8.0);
@ -395,4 +406,38 @@ impl Content {
}); });
ui.add_space(6.0); ui.add_space(6.0);
} }
/// Draw content for integrated node warning [`Modal`] on Android.
fn crash_report_modal_ui(&mut self,
ui: &mut egui::Ui,
modal: &Modal,
cb: &dyn PlatformCallbacks) {
ui.add_space(6.0);
ui.vertical_centered(|ui| {
ui.label(RichText::new(t!("crash_report_warning"))
.size(16.0)
.color(Colors::text(false)));
ui.add_space(6.0);
// Draw button to share crash report.
let text = format!("{} {}", FILE_X, t!("share"));
View::colored_text_button(ui, text, Colors::blue(), Colors::white_or_black(false), || {
if let Ok(data) = fs::read_to_string(Settings::crash_report_path()) {
cb.share_data(Settings::CRASH_REPORT_FILE_NAME.to_string(),
data.as_bytes().to_vec()).unwrap_or_default()
}
AppConfig::set_show_crash(false);
modal.close();
});
});
ui.add_space(8.0);
View::horizontal_line(ui, Colors::item_stroke());
ui.add_space(8.0);
ui.vertical_centered_justified(|ui| {
View::button(ui, t!("modal.cancel"), Colors::white_or_black(false), || {
AppConfig::set_show_crash(false);
modal.close();
});
});
ui.add_space(6.0);
}
} }

View file

@ -29,19 +29,41 @@ fn real_main() {
.parse_default_env() .parse_default_env()
.init(); .init();
use grim::gui::platform::Desktop; // Setup callback on panic crash.
use grim::gui::App; std::panic::set_hook(Box::new(|info| {
let backtrace = backtrace::Backtrace::new();
// Format error.
let time = grim::gui::views::View::format_time(chrono::Utc::now().timestamp());
let target = egui::os::OperatingSystem::from_target_os();
let ver = grim::VERSION;
let msg = panic_message::panic_info_message(info);
let err = format!("{} - {:?} - v{}\n\n{}\n\n{:?}", time, target, ver, msg, backtrace);
// Save backtrace to file.
let log = grim::Settings::crash_report_path();
if log.exists() {
std::fs::remove_file(log.clone()).unwrap();
}
std::fs::write(log, err.as_bytes()).unwrap();
// Setup flag to show crash after app restart.
grim::AppConfig::set_show_crash(true);
}));
// Start GUI.
let _ = std::panic::catch_unwind(|| {
start_desktop_gui();
});
}
/// Start GUI with Desktop related setup.
#[allow(dead_code)]
#[cfg(not(target_os = "android"))]
fn start_desktop_gui() {
use grim::AppConfig; use grim::AppConfig;
use dark_light::Mode;
use std::sync::Arc; let platform = grim::gui::platform::Desktop::default();
use egui::pos2;
use egui::os::OperatingSystem;
use eframe::icon_data::from_png_bytes;
let platform = Desktop::default();
// Setup system theme if not set. // Setup system theme if not set.
use dark_light::Mode;
if let None = AppConfig::dark_theme() { if let None = AppConfig::dark_theme() {
let dark = match dark_light::detect() { let dark = match dark_light::detect() {
Mode::Dark => true, Mode::Dark => true,
@ -57,49 +79,46 @@ fn real_main() {
let mut viewport = egui::ViewportBuilder::default() let mut viewport = egui::ViewportBuilder::default()
.with_min_inner_size([AppConfig::MIN_WIDTH, AppConfig::MIN_HEIGHT]) .with_min_inner_size([AppConfig::MIN_WIDTH, AppConfig::MIN_HEIGHT])
.with_inner_size([width, height]); .with_inner_size([width, height]);
// Setup an icon. // Setup an icon.
if let Ok(icon) = from_png_bytes(include_bytes!("../img/icon.png")) { if let Ok(icon) = eframe::icon_data::from_png_bytes(include_bytes!("../img/icon.png")) {
viewport = viewport.with_icon(Arc::new(icon)); viewport = viewport.with_icon(std::sync::Arc::new(icon));
} }
// Setup window position. // Setup window position.
if let Some((x, y)) = AppConfig::window_pos() { if let Some((x, y)) = AppConfig::window_pos() {
viewport = viewport.with_position(pos2(x, y)); viewport = viewport.with_position(egui::pos2(x, y));
} }
// Setup window decorations. // Setup window decorations.
let is_mac_os = OperatingSystem::from_target_os() == OperatingSystem::Mac; let is_mac = egui::os::OperatingSystem::from_target_os() == egui::os::OperatingSystem::Mac;
viewport = viewport viewport = viewport
.with_fullsize_content_view(true) .with_fullsize_content_view(true)
.with_title_shown(false) .with_title_shown(false)
.with_titlebar_buttons_shown(false) .with_titlebar_buttons_shown(false)
.with_titlebar_shown(false) .with_titlebar_shown(false)
.with_transparent(true) .with_transparent(true)
.with_decorations(is_mac_os); .with_decorations(is_mac);
let mut options = eframe::NativeOptions { let mut options = eframe::NativeOptions {
viewport, viewport,
..Default::default() ..Default::default()
}; };
// Use Glow renderer for Windows. // Use Glow renderer for Windows.
let is_windows = OperatingSystem::from_target_os() == OperatingSystem::Windows; let win = egui::os::OperatingSystem::from_target_os() == egui::os::OperatingSystem::Windows;
options.renderer = if is_windows { options.renderer = if win {
eframe::Renderer::Glow eframe::Renderer::Glow
} else { } else {
eframe::Renderer::Wgpu eframe::Renderer::Wgpu
}; };
match grim::start(options.clone(), grim::app_creator(App::new(platform.clone()))) { // Start GUI.
match grim::start(options.clone(), grim::app_creator(grim::gui::App::new(platform.clone()))) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
if is_windows { if win {
panic!("{}", e); panic!("{}", e);
} }
// Start with another renderer on error. // Start with another renderer on error.
options.renderer = eframe::Renderer::Glow; options.renderer = eframe::Renderer::Glow;
match grim::start(options, grim::app_creator(App::new(platform))) { match grim::start(options, grim::app_creator(grim::gui::App::new(platform))) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
panic!("{}", e); panic!("{}", e);

View file

@ -47,7 +47,7 @@ impl PeersConfig {
/// Save peers config to the file. /// Save peers config to the file.
pub fn save(&self) { pub fn save(&self) {
let chain_type = AppConfig::chain_type(); let chain_type = AppConfig::chain_type();
let config_path = Settings::get_config_path(Self::FILE_NAME, Some(chain_type.shortname())); let config_path = Settings::config_path(Self::FILE_NAME, Some(chain_type.shortname()));
Settings::write_to_file(self, config_path); Settings::write_to_file(self, config_path);
// Load changes to node server config. // Load changes to node server config.
Self::load_to_server_config(); Self::load_to_server_config();
@ -149,7 +149,7 @@ impl NodeConfig {
// Initialize peers config. // Initialize peers config.
let peers_config = { let peers_config = {
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
let path = Settings::get_config_path(PeersConfig::FILE_NAME, sub_dir); let path = Settings::config_path(PeersConfig::FILE_NAME, sub_dir);
let config = Settings::read_from_file::<PeersConfig>(path.clone()); let config = Settings::read_from_file::<PeersConfig>(path.clone());
if !path.exists() || config.is_err() { if !path.exists() || config.is_err() {
Self::save_default_peers_config(chain_type) Self::save_default_peers_config(chain_type)
@ -161,7 +161,7 @@ impl NodeConfig {
// Initialize node config. // Initialize node config.
let node_config = { let node_config = {
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
let path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, sub_dir); let path = Settings::config_path(SERVER_CONFIG_FILE_NAME, sub_dir);
let config = Settings::read_from_file::<ConfigMembers>(path.clone()); let config = Settings::read_from_file::<ConfigMembers>(path.clone());
if !path.exists() || config.is_err() { if !path.exists() || config.is_err() {
Self::save_default_node_server_config(chain_type) Self::save_default_node_server_config(chain_type)
@ -176,10 +176,10 @@ impl NodeConfig {
/// Save default node config for specified [`ChainTypes`]. /// Save default node config for specified [`ChainTypes`].
fn save_default_node_server_config(chain_type: &ChainTypes) -> ConfigMembers { fn save_default_node_server_config(chain_type: &ChainTypes) -> ConfigMembers {
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
let path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, sub_dir.clone()); let path = Settings::config_path(SERVER_CONFIG_FILE_NAME, sub_dir.clone());
let mut default_config = GlobalConfig::for_chain(chain_type); let mut default_config = GlobalConfig::for_chain(chain_type);
default_config.update_paths(&Settings::get_base_path(sub_dir)); default_config.update_paths(&Settings::base_path(sub_dir));
let mut config = default_config.members.unwrap(); let mut config = default_config.members.unwrap();
// Generate random p2p and api ports. // Generate random p2p and api ports.
@ -214,7 +214,7 @@ impl NodeConfig {
/// Save default peers config for specified [`ChainTypes`]. /// Save default peers config for specified [`ChainTypes`].
fn save_default_peers_config(chain_type: &ChainTypes) -> PeersConfig { fn save_default_peers_config(chain_type: &ChainTypes) -> PeersConfig {
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
let path = Settings::get_config_path(PeersConfig::FILE_NAME, sub_dir); let path = Settings::config_path(PeersConfig::FILE_NAME, sub_dir);
let config = PeersConfig::default(); let config = PeersConfig::default();
Settings::write_to_file(&config, path); Settings::write_to_file(&config, path);
config config
@ -223,7 +223,7 @@ impl NodeConfig {
/// Save node config to the file. /// Save node config to the file.
pub fn save(&self) { pub fn save(&self) {
let sub_dir = Some(self.node.server.chain_type.shortname()); let sub_dir = Some(self.node.server.chain_type.shortname());
let config_path = Settings::get_config_path(SERVER_CONFIG_FILE_NAME, sub_dir); let config_path = Settings::config_path(SERVER_CONFIG_FILE_NAME, sub_dir);
Settings::write_to_file(&self.node, config_path); Settings::write_to_file(&self.node, config_path);
} }
@ -264,7 +264,7 @@ impl NodeConfig {
/// Get path for secret file. /// Get path for secret file.
fn get_secret_path(chain_type: &ChainTypes, secret_file_name: &str) -> PathBuf { fn get_secret_path(chain_type: &ChainTypes, secret_file_name: &str) -> PathBuf {
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
let grin_path = Settings::get_base_path(sub_dir); let grin_path = Settings::base_path(sub_dir);
let mut api_secret_path = grin_path; let mut api_secret_path = grin_path;
api_secret_path.push(secret_file_name); api_secret_path.push(secret_file_name);
api_secret_path api_secret_path

View file

@ -49,6 +49,9 @@ pub struct AppConfig {
/// Flag to check if dark theme should be used, use system settings if not set. /// Flag to check if dark theme should be used, use system settings if not set.
use_dark_theme: Option<bool>, use_dark_theme: Option<bool>,
/// Flag to show crash report when happened.
show_crash: Option<bool>
} }
impl Default for AppConfig { impl Default for AppConfig {
@ -65,6 +68,7 @@ impl Default for AppConfig {
y: None, y: None,
lang: None, lang: None,
use_dark_theme: None, use_dark_theme: None,
show_crash: None,
} }
} }
} }
@ -89,7 +93,7 @@ impl AppConfig {
/// Save application configuration to the file. /// Save application configuration to the file.
pub fn save(&self) { pub fn save(&self) {
Settings::write_to_file(self, Settings::get_config_path(Self::FILE_NAME, None)); Settings::write_to_file(self, Settings::config_path(Self::FILE_NAME, None));
} }
/// Change global [`ChainTypes`] and load new [`NodeConfig`]. /// Change global [`ChainTypes`] and load new [`NodeConfig`].
@ -241,4 +245,17 @@ impl AppConfig {
w_config.use_dark_theme = Some(use_dark); w_config.use_dark_theme = Some(use_dark);
w_config.save(); w_config.save();
} }
/// Check if crash report should be shown on application start.
pub fn show_crash() -> bool {
let r_config = Settings::app_config_to_read();
r_config.show_crash.unwrap_or(false)
}
/// Setup flag to show crash report on application start.
pub fn set_show_crash(show: bool) {
let mut w_config = Settings::app_config_to_update();
w_config.show_crash = Some(show);
w_config.save();
}
} }

View file

@ -33,9 +33,6 @@ lazy_static! {
static ref SETTINGS_STATE: Arc<Settings> = Arc::new(Settings::init()); static ref SETTINGS_STATE: Arc<Settings> = Arc::new(Settings::init());
} }
/// Main application directory name.
const MAIN_DIR_NAME: &'static str = ".grim";
/// Contains initialized configurations. /// Contains initialized configurations.
pub struct Settings { pub struct Settings {
/// Application configuration. /// Application configuration.
@ -49,14 +46,20 @@ pub struct Settings {
} }
impl Settings { impl Settings {
/// Main application directory name.
pub const MAIN_DIR_NAME: &'static str = ".grim";
/// Crash report file name.
pub const CRASH_REPORT_FILE_NAME: &'static str = "crash.log";
/// Initialize settings with app and node configs. /// Initialize settings with app and node configs.
fn init() -> Self { fn init() -> Self {
// Initialize app config. // Initialize app config.
let app_config_path = Settings::get_config_path(AppConfig::FILE_NAME, None); let app_config_path = Settings::config_path(AppConfig::FILE_NAME, None);
let app_config = Self::init_config::<AppConfig>(app_config_path); let app_config = Self::init_config::<AppConfig>(app_config_path);
// Initialize tor config. // Initialize tor config.
let tor_config_path = Settings::get_config_path(TorConfig::FILE_NAME, None); let tor_config_path = Settings::config_path(TorConfig::FILE_NAME, None);
let tor_config = Self::init_config::<TorConfig>(tor_config_path); let tor_config = Self::init_config::<TorConfig>(tor_config_path);
let chain_type = &app_config.chain_type; let chain_type = &app_config.chain_type;
@ -121,13 +124,13 @@ impl Settings {
} }
/// Get base directory path for configuration. /// Get base directory path for configuration.
pub fn get_base_path(sub_dir: Option<String>) -> PathBuf { pub fn base_path(sub_dir: Option<String>) -> 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,
None => PathBuf::new(), None => PathBuf::new(),
}; };
path.push(MAIN_DIR_NAME); path.push(Self::MAIN_DIR_NAME);
if sub_dir.is_some() { if sub_dir.is_some() {
path.push(sub_dir.unwrap()); path.push(sub_dir.unwrap());
} }
@ -139,10 +142,17 @@ impl Settings {
} }
/// Get configuration file path from provided name and sub-directory if needed. /// Get configuration file path from provided name and sub-directory if needed.
pub fn get_config_path(config_name: &str, sub_dir: Option<String>) -> PathBuf { pub fn config_path(config_name: &str, sub_dir: Option<String>) -> PathBuf {
let mut settings_path = Self::get_base_path(sub_dir); let mut path = Self::base_path(sub_dir);
settings_path.push(config_name); path.push(config_name);
settings_path path
}
/// Get configuration file path from provided name and sub-directory if needed.
pub fn crash_report_path() -> PathBuf {
let mut path = Self::base_path(None);
path.push(Self::CRASH_REPORT_FILE_NAME);
path
} }
/// Read configuration from the file. /// Read configuration from the file.

View file

@ -61,12 +61,12 @@ impl TorConfig {
/// Save application configuration to the file. /// Save application configuration to the file.
pub fn save(&self) { pub fn save(&self) {
Settings::write_to_file(self, Settings::get_config_path(Self::FILE_NAME, None)); Settings::write_to_file(self, Settings::config_path(Self::FILE_NAME, None));
} }
/// Get path from subdirectory name. /// Get path from subdirectory name.
fn sub_dir_path(name: &str) -> String { fn sub_dir_path(name: &str) -> String {
let mut base = Settings::get_base_path(Some(Self::DIR_NAME.to_string())); let mut base = Settings::base_path(Some(Self::DIR_NAME.to_string()));
base.push(name); base.push(name);
base.to_str().unwrap().to_string() base.to_str().unwrap().to_string()
} }

View file

@ -125,7 +125,7 @@ impl WalletConfig {
/// Get wallets base directory path for provided [`ChainTypes`]. /// Get wallets base directory path for provided [`ChainTypes`].
pub fn get_base_path(chain_type: ChainTypes) -> PathBuf { pub fn get_base_path(chain_type: ChainTypes) -> PathBuf {
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
let mut wallets_path = Settings::get_base_path(sub_dir); let mut wallets_path = Settings::base_path(sub_dir);
wallets_path.push(BASE_DIR_NAME); wallets_path.push(BASE_DIR_NAME);
// Create wallets base directory if it doesn't exist. // Create wallets base directory if it doesn't exist.
if !wallets_path.exists() { if !wallets_path.exists() {

View file

@ -33,7 +33,7 @@ impl ConnectionsConfig {
/// Initialize configuration for provided [`ChainTypes`]. /// Initialize configuration for provided [`ChainTypes`].
pub fn for_chain_type(chain_type: &ChainTypes) -> Self { pub fn for_chain_type(chain_type: &ChainTypes) -> Self {
let path = Settings::get_config_path(Self::FILE_NAME, Some(chain_type.shortname())); let path = Settings::config_path(Self::FILE_NAME, Some(chain_type.shortname()));
let parsed = Settings::read_from_file::<ConnectionsConfig>(path.clone()); let parsed = Settings::read_from_file::<ConnectionsConfig>(path.clone());
if !path.exists() || parsed.is_err() { if !path.exists() || parsed.is_err() {
let default_config = ConnectionsConfig { let default_config = ConnectionsConfig {
@ -57,7 +57,7 @@ impl ConnectionsConfig {
pub fn save(&self) { pub fn save(&self) {
let chain_type = AppConfig::chain_type(); let chain_type = AppConfig::chain_type();
let sub_dir = Some(chain_type.shortname()); let sub_dir = Some(chain_type.shortname());
Settings::write_to_file(self, Settings::get_config_path(Self::FILE_NAME, sub_dir)); Settings::write_to_file(self, Settings::config_path(Self::FILE_NAME, sub_dir));
} }
/// Get [`ExternalConnection`] list. /// Get [`ExternalConnection`] list.