From 9577e6a227a85aa3a2f337a52b0f2904ed836bdf Mon Sep 17 00:00:00 2001 From: edouard Date: Mon, 13 Mar 2023 14:47:11 +0100 Subject: [PATCH] gui: make daemon config optional If no daemon config path is present in the gui config, gui will try first to connect to the socket pat, either `daemon_rpc_path` if present in configuration file or default path. close #147 --- gui/src/app/config.rs | 7 ++++-- gui/src/app/mod.rs | 14 ++++++++--- gui/src/launcher.rs | 20 +++++++-------- gui/src/loader.rs | 36 ++++++++++++++------------- gui/src/main.rs | 58 ++++++++++++++++++++++++++++++------------- 5 files changed, 85 insertions(+), 50 deletions(-) diff --git a/gui/src/app/config.rs b/gui/src/app/config.rs index 5d8d0b11..265221f4 100644 --- a/gui/src/app/config.rs +++ b/gui/src/app/config.rs @@ -6,7 +6,9 @@ use tracing_subscriber::filter; #[derive(Debug, Clone, Deserialize, Serialize)] pub struct Config { /// Path to lianad configuration file. - pub daemon_config_path: PathBuf, + pub daemon_config_path: Option, + /// Path to lianad_rpc socket file. + pub daemon_rpc_path: Option, /// log level, can be "info", "debug", "trace". pub log_level: Option, /// Use iced debug feature if true. @@ -21,7 +23,8 @@ pub const DEFAULT_FILE_NAME: &str = "gui.toml"; impl Config { pub fn new(daemon_config_path: PathBuf) -> Self { Self { - daemon_config_path, + daemon_config_path: Some(daemon_config_path), + daemon_rpc_path: None, log_level: None, debug: None, hardware_wallets: None, diff --git a/gui/src/app/mod.rs b/gui/src/app/mod.rs index aa1b8163..7b46bcf4 100644 --- a/gui/src/app/mod.rs +++ b/gui/src/app/mod.rs @@ -11,6 +11,7 @@ mod error; use std::fs::OpenOptions; use std::io::Write; +use std::path::PathBuf; use std::sync::Arc; use std::time::Duration; @@ -138,7 +139,10 @@ impl App { ) } Message::LoadDaemonConfig(cfg) => { - let res = self.load_daemon_config(*cfg); + let path = self.config.daemon_config_path.clone().expect( + "Application config must have a daemon configuration file path at this point.", + ); + let res = self.load_daemon_config(&path, *cfg); self.update(Message::DaemonConfigLoaded(res)) } Message::View(view::Message::Menu(menu)) => self.load_state(&menu), @@ -147,7 +151,11 @@ impl App { } } - pub fn load_daemon_config(&mut self, cfg: DaemonConfig) -> Result<(), Error> { + pub fn load_daemon_config( + &mut self, + daemon_config_path: &PathBuf, + cfg: DaemonConfig, + ) -> Result<(), Error> { loop { if let Some(daemon) = Arc::get_mut(&mut self.daemon) { daemon.load_config(cfg)?; @@ -157,7 +165,7 @@ impl App { let mut daemon_config_file = OpenOptions::new() .write(true) - .open(&self.config.daemon_config_path) + .open(daemon_config_path) .map_err(|e| Error::Config(e.to_string()))?; let content = diff --git a/gui/src/launcher.rs b/gui/src/launcher.rs index 1e71046a..74ab36bf 100644 --- a/gui/src/launcher.rs +++ b/gui/src/launcher.rs @@ -69,13 +69,9 @@ impl Launcher { path.push(network.to_string()); path.push(app::config::DEFAULT_FILE_NAME); let cfg = app::Config::from_file(&path).expect("Already checked"); - let daemon_cfg = - liana::config::Config::from_file(Some(cfg.daemon_config_path.clone())) - .expect("Already checked"); - Command::perform( - async move { (datadir_path.clone(), cfg, daemon_cfg) }, - |m| Message::Run(m.0, m.1, m.2), - ) + Command::perform(async move { (datadir_path.clone(), cfg, network) }, |m| { + Message::Run(m.0, m.1, m.2) + }) } }, _ => Command::none(), @@ -157,7 +153,7 @@ pub enum Message { View(ViewMessage), Install(PathBuf), Checked(Result), - Run(PathBuf, app::config::Config, liana::config::Config), + Run(PathBuf, app::config::Config, Network), } #[derive(Debug, Clone)] @@ -177,12 +173,13 @@ async fn check_network_datadir(mut path: PathBuf, network: Network) -> Result { format!( "Failed to read daemon configuration file in the directory: {}", - cfg.daemon_config_path.to_string_lossy() + daemon_config_path.to_string_lossy() ) } ConfigError::ReadingFile(e) => { @@ -191,7 +188,7 @@ async fn check_network_datadir(mut path: PathBuf, network: Network) -> Result Result (Self, Command) { - let path = socket_path(&datadir_path, daemon_config.bitcoin_config.network); - let network = daemon_config.bitcoin_config.network; + let path = gui_config + .daemon_rpc_path + .clone() + .unwrap_or_else(|| socket_path(&datadir_path, network)); + let network = network; ( Loader { network, datadir_path, - daemon_config: daemon_config.clone(), gui_config, step: Step::Connecting, daemon_started: false, }, - Command::perform(connect(path, daemon_config), Message::Loaded), + Command::perform(connect(path), Message::Loaded), ) } @@ -103,12 +104,16 @@ impl Loader { Error::Daemon(DaemonError::ClientNotSupported) | Error::Daemon(DaemonError::Transport(Some(ErrorKind::ConnectionRefused), _)) | Error::Daemon(DaemonError::Transport(Some(ErrorKind::NotFound), _)) => { - self.step = Step::StartingDaemon; - self.daemon_started = true; - return Command::perform( - start_daemon(self.gui_config.daemon_config_path.clone()), - Message::Started, - ); + if let Some(daemon_config_path) = self.gui_config.daemon_config_path.clone() { + self.step = Step::StartingDaemon; + self.daemon_started = true; + return Command::perform( + start_daemon(daemon_config_path), + Message::Started, + ); + } else { + self.step = Step::Error(Box::new(e)); + } } _ => { self.step = Step::Error(Box::new(e)); @@ -187,7 +192,7 @@ impl Loader { let (loader, cmd) = Self::new( self.datadir_path.clone(), self.gui_config.clone(), - self.daemon_config.clone(), + self.network, ); *self = loader; cmd @@ -361,10 +366,7 @@ pub fn cover<'a, T: 'a + Clone, C: Into>>( .into() } -async fn connect( - socket_path: PathBuf, - _config: Config, -) -> Result, Error> { +async fn connect(socket_path: PathBuf) -> Result, Error> { let client = client::jsonrpc::JsonRPCClient::new(socket_path); let daemon = Lianad::new(client); diff --git a/gui/src/main.rs b/gui/src/main.rs index 914a10e6..8f15ce38 100644 --- a/gui/src/main.rs +++ b/gui/src/main.rs @@ -123,15 +123,13 @@ impl Application for GUI { ]), ) } - Config::Run(datadir_path, cfg) => { - let daemon_cfg = - DaemonConfig::from_file(Some(cfg.daemon_config_path.clone())).unwrap(); + Config::Run(datadir_path, cfg, network) => { logger.set_running_mode( datadir_path.clone(), - daemon_cfg.bitcoin_config.network, + network, cfg.log_level().unwrap_or(LevelFilter::INFO), ); - let (loader, command) = Loader::new(datadir_path, cfg, daemon_cfg); + let (loader, command) = Loader::new(datadir_path, cfg, network); ( Self { state: State::Loader(Box::new(loader)), @@ -172,13 +170,13 @@ impl Application for GUI { self.state = State::Installer(Box::new(install)); command.map(|msg| Message::Install(Box::new(msg))) } - launcher::Message::Run(datadir_path, cfg, daemon_cfg) => { + launcher::Message::Run(datadir_path, cfg, network) => { self.logger.set_running_mode( datadir_path.clone(), - daemon_cfg.bitcoin_config.network, + network, cfg.log_level().unwrap_or(LevelFilter::INFO), ); - let (loader, command) = Loader::new(datadir_path, cfg, daemon_cfg); + let (loader, command) = Loader::new(datadir_path, cfg, network); self.state = State::Loader(Box::new(loader)); command.map(|msg| Message::Load(Box::new(msg))) } @@ -188,7 +186,7 @@ impl Application for GUI { if let installer::Message::Exit(path) = *msg { let cfg = app::Config::from_file(&path).unwrap(); let daemon_cfg = - DaemonConfig::from_file(Some(cfg.daemon_config_path.clone())).unwrap(); + DaemonConfig::from_file(cfg.daemon_config_path.clone()).unwrap(); let datadir_path = daemon_cfg .data_dir .as_ref() @@ -201,7 +199,8 @@ impl Application for GUI { cfg.log_level().unwrap_or(LevelFilter::INFO), ); self.logger.remove_install_log_file(datadir_path.clone()); - let (loader, command) = Loader::new(datadir_path, cfg, daemon_cfg); + let (loader, command) = + Loader::new(datadir_path, cfg, daemon_cfg.bitcoin_config.network); self.state = State::Loader(Box::new(loader)); command.map(|msg| Message::Load(Box::new(msg))) } else { @@ -255,7 +254,7 @@ impl Application for GUI { } pub enum Config { - Run(PathBuf, app::Config), + Run(PathBuf, app::Config, bitcoin::Network), Launcher(PathBuf), Install(PathBuf, bitcoin::Network), } @@ -270,7 +269,7 @@ impl Config { path.push(network.to_string()); path.push(app::config::DEFAULT_FILE_NAME); match app::Config::from_file(&path) { - Ok(cfg) => Ok(Config::Run(datadir_path, cfg)), + Ok(cfg) => Ok(Config::Run(datadir_path, cfg, network)), Err(ConfigError::NotFound) => Ok(Config::Install(datadir_path, network)), Err(e) => Err(format!("Failed to read configuration file: {}", e).into()), } @@ -295,11 +294,36 @@ fn main() -> Result<(), Box> { } [Arg::ConfigPath(path)] => { let cfg = app::Config::from_file(path)?; - let daemon_cfg = DaemonConfig::from_file(Some(cfg.daemon_config_path.clone()))?; - let datadir_path = daemon_cfg - .data_dir - .unwrap_or_else(|| default_datadir().unwrap()); - Ok(Config::Run(datadir_path, cfg)) + if let Some(daemon_config_path) = cfg.daemon_config_path.clone() { + let daemon_cfg = DaemonConfig::from_file(Some(daemon_config_path))?; + let datadir_path = daemon_cfg + .data_dir + .unwrap_or_else(|| default_datadir().unwrap()); + Ok(Config::Run( + datadir_path, + cfg, + daemon_cfg.bitcoin_config.network, + )) + } else { + Err("Application cannot guess network".into()) + } + } + [Arg::ConfigPath(path), Arg::Network(network)] + | [Arg::Network(network), Arg::ConfigPath(path)] => { + let cfg = app::Config::from_file(path)?; + if let Some(daemon_config_path) = cfg.daemon_config_path.clone() { + let daemon_cfg = DaemonConfig::from_file(Some(daemon_config_path))?; + let datadir_path = daemon_cfg + .data_dir + .unwrap_or_else(|| default_datadir().unwrap()); + Ok(Config::Run( + datadir_path, + cfg, + daemon_cfg.bitcoin_config.network, + )) + } else { + Ok(Config::Run(default_datadir().unwrap(), cfg, *network)) + } } [Arg::DatadirPath(datadir_path)] => Config::new(datadir_path.clone(), None), [Arg::DatadirPath(datadir_path), Arg::Network(network)]