diff --git a/gui/src/installer/config.rs b/gui/src/installer/config.rs index 9ee70f65..5d5ec8fb 100644 --- a/gui/src/installer/config.rs +++ b/gui/src/installer/config.rs @@ -1,80 +1,26 @@ use std::convert::TryFrom; -use minisafe::{ - config::{BitcoinConfig, BitcoindConfig, Config as MinisafeConfig}, - descriptors::InheritanceDescriptor, - miniscript::bitcoin::Network, -}; +use minisafe::config::Config as MinisafeConfig; -use serde::Serialize; -use std::{net::SocketAddr, path::PathBuf, time::Duration}; +use super::step::Context; -/// Static informations we require to operate -/// fields with default values are not present, see minisafe::config. -#[derive(Debug, Clone, Serialize)] -pub struct Config { - #[serde(serialize_with = "serialize_option_to_string")] - pub main_descriptor: Option, - pub bitcoin_config: BitcoinConfig, - /// Everything we need to know to talk to bitcoind - pub bitcoind_config: BitcoindConfig, - /// An optional custom data directory - pub data_dir: Option, -} +pub const DEFAULT_FILE_NAME: &str = "daemon.toml"; -impl Config { - pub const DEFAULT_FILE_NAME: &'static str = "daemon.toml"; - /// returns a minisafed config with empty or dummy values - pub fn new() -> Config { - Self { - main_descriptor: None, - bitcoin_config: BitcoinConfig { - network: Network::Bitcoin, - poll_interval_secs: Duration::from_secs(30), - }, - bitcoind_config: BitcoindConfig { - cookie_path: PathBuf::new(), - addr: SocketAddr::new( - std::net::IpAddr::V4(std::net::Ipv4Addr::new(127, 0, 0, 1)), - 8080, - ), - }, - data_dir: None, - } - } -} - -impl Default for Config { - fn default() -> Self { - Self::new() - } -} - -pub fn serialize_option_to_string( - field: &Option, - s: S, -) -> Result { - match field { - Some(field) => s.serialize_str(&field.to_string()), - None => s.serialize_none(), - } -} - -impl TryFrom for MinisafeConfig { +impl TryFrom for MinisafeConfig { type Error = &'static str; - fn try_from(cfg: Config) -> Result { - if cfg.main_descriptor.is_none() { + fn try_from(ctx: Context) -> Result { + if ctx.descriptor.is_none() { return Err("config does not have a main Descriptor"); } Ok(MinisafeConfig { #[cfg(unix)] daemon: false, log_level: log::LevelFilter::Info, - main_descriptor: cfg.main_descriptor.unwrap(), - data_dir: cfg.data_dir, - bitcoin_config: cfg.bitcoin_config, - bitcoind_config: Some(cfg.bitcoind_config), + main_descriptor: ctx.descriptor.unwrap(), + data_dir: ctx.data_dir, + bitcoin_config: ctx.bitcoin_config, + bitcoind_config: ctx.bitcoind_config, }) } } diff --git a/gui/src/installer/mod.rs b/gui/src/installer/mod.rs index b67e947a..1bc8a2f1 100644 --- a/gui/src/installer/mod.rs +++ b/gui/src/installer/mod.rs @@ -12,7 +12,7 @@ use std::convert::TryInto; use std::io::Write; use std::path::PathBuf; -use crate::{app::config as gui_config, installer::config::Config as DaemonConfig}; +use crate::{app::config as gui_config, installer::config::DEFAULT_FILE_NAME}; pub use message::Message; use step::{Context, DefineBitcoind, DefineDescriptor, Final, Step, Welcome}; @@ -24,7 +24,6 @@ pub struct Installer { /// Context is data passed through each step. context: Context, - config: DaemonConfig, } impl Installer { @@ -44,12 +43,9 @@ impl Installer { destination_path: PathBuf, network: bitcoin::Network, ) -> (Installer, Command) { - let mut config = DaemonConfig::new(); - config.data_dir = Some(destination_path); ( Installer { should_exit: false, - config, current: 0, steps: vec![ Welcome::new(network).into(), @@ -57,7 +53,7 @@ impl Installer { DefineBitcoind::new().into(), Final::new().into(), ], - context: Context::new(network), + context: Context::new(network, Some(destination_path)), }, Command::none(), ) @@ -82,7 +78,7 @@ impl Installer { .steps .get_mut(self.current) .expect("There is always a step"); - if current_step.apply(&mut self.context, &mut self.config) { + if current_step.apply(&mut self.context) { self.next(); // skip the step according to the current context. while self @@ -111,10 +107,7 @@ impl Installer { .get_mut(self.current) .expect("There is always a step") .update(message); - Command::perform( - install(self.context.clone(), self.config.clone()), - Message::Installed, - ) + Command::perform(install(self.context.clone()), Message::Installed) } Message::Event(Event::Window(window::Event::CloseRequested)) => { self.stop(); @@ -136,12 +129,14 @@ impl Installer { } } -pub async fn install(_ctx: Context, mut cfg: DaemonConfig) -> Result { +pub async fn install(ctx: Context) -> Result { + let mut cfg: minisafe::config::Config = ctx + .try_into() + .expect("Everything should be checked at this point"); // Start Daemon to check correctness of installation - let daemon = - minisafe::DaemonHandle::start_default(cfg.clone().try_into().unwrap()).map_err(|e| { - Error::Unexpected(format!("Failed to start daemon with entered config: {}", e)) - })?; + let daemon = minisafe::DaemonHandle::start_default(cfg.clone()).map_err(|e| { + Error::Unexpected(format!("Failed to start daemon with entered config: {}", e)) + })?; daemon.shutdown(); cfg.data_dir = @@ -154,7 +149,7 @@ pub async fn install(_ctx: Context, mut cfg: DaemonConfig) -> Result bool { + fn apply(&mut self, ctx: &mut Context) -> bool { // descriptor forms for import or creation cannot be both empty or filled. if self.imported_descriptor.value.is_empty() == (self.user_xpub.value.is_empty() @@ -125,7 +124,7 @@ impl Step for DefineDescriptor { false } else if !self.imported_descriptor.value.is_empty() { if let Ok(desc) = InheritanceDescriptor::from_str(&self.imported_descriptor.value) { - config.main_descriptor = Some(desc); + ctx.descriptor = Some(desc); true } else { self.imported_descriptor.valid = false; @@ -145,20 +144,20 @@ impl Step for DefineDescriptor { return false; } - match InheritanceDescriptor::new( + let desc = match InheritanceDescriptor::new( user_key.unwrap(), heir_key.unwrap(), sequence.unwrap(), ) { - Ok(desc) => { - config.main_descriptor = Some(desc); - true - } + Ok(desc) => desc, Err(e) => { self.error = Some(e.to_string()); - false + return false; } - } + }; + + ctx.descriptor = Some(desc); + true } } diff --git a/gui/src/installer/step/mod.rs b/gui/src/installer/step/mod.rs index 20d55249..91955994 100644 --- a/gui/src/installer/step/mod.rs +++ b/gui/src/installer/step/mod.rs @@ -3,14 +3,18 @@ pub use descriptor::DefineDescriptor; use std::path::PathBuf; use std::str::FromStr; +use std::time::Duration; use iced::{pure::Element, Command}; -use minisafe::miniscript::bitcoin; +use minisafe::{ + config::{BitcoinConfig, BitcoindConfig}, + descriptors::InheritanceDescriptor, + miniscript::bitcoin, +}; use crate::ui::component::form; use crate::installer::{ - config, message::{self, Message}, view, }; @@ -24,25 +28,30 @@ pub trait Step { fn skip(&self, _ctx: &Context) -> bool { false } - fn apply(&mut self, _ctx: &mut Context, _config: &mut config::Config) -> bool { + fn apply(&mut self, _ctx: &mut Context) -> bool { true } } #[derive(Clone)] pub struct Context { - pub network: bitcoin::Network, + pub bitcoin_config: BitcoinConfig, + pub bitcoind_config: Option, + pub descriptor: Option, + pub data_dir: Option, } impl Context { - pub fn new(network: bitcoin::Network) -> Self { - Self { network } - } -} - -impl Default for Context { - fn default() -> Self { - Self::new(bitcoin::Network::Bitcoin) + pub fn new(network: bitcoin::Network, data_dir: Option) -> Self { + Self { + bitcoin_config: BitcoinConfig { + network, + poll_interval_secs: Duration::from_secs(30), + }, + bitcoind_config: None, + descriptor: None, + data_dir, + } } } @@ -63,9 +72,8 @@ impl Step for Welcome { } Command::none() } - fn apply(&mut self, ctx: &mut Context, config: &mut config::Config) -> bool { - ctx.network = self.network; - config.bitcoin_config.network = self.network; + fn apply(&mut self, ctx: &mut Context) -> bool { + ctx.bitcoin_config.network = self.network; true } fn view(&self) -> Element { @@ -145,10 +153,11 @@ impl DefineBitcoind { impl Step for DefineBitcoind { fn load_context(&mut self, ctx: &Context) { if self.cookie_path.value.is_empty() { - self.cookie_path.value = bitcoind_default_cookie_path(&ctx.network).unwrap_or_default() + self.cookie_path.value = + bitcoind_default_cookie_path(&ctx.bitcoin_config.network).unwrap_or_default() } if self.address.value.is_empty() { - self.address.value = bitcoind_default_address(&ctx.network); + self.address.value = bitcoind_default_address(&ctx.bitcoin_config.network); } } fn update(&mut self, message: Message) -> Command { @@ -167,7 +176,7 @@ impl Step for DefineBitcoind { Command::none() } - fn apply(&mut self, _ctx: &mut Context, config: &mut config::Config) -> bool { + fn apply(&mut self, ctx: &mut Context) -> bool { match ( PathBuf::from_str(&self.cookie_path.value), std::net::SocketAddr::from_str(&self.address.value), @@ -186,8 +195,10 @@ impl Step for DefineBitcoind { false } (Ok(path), Ok(addr)) => { - config.bitcoind_config.cookie_path = path; - config.bitcoind_config.addr = addr; + ctx.bitcoind_config = Some(BitcoindConfig { + cookie_path: path, + addr, + }); true } }