installer: refac context

This commit is contained in:
edouard 2022-10-25 15:52:52 +02:00
parent 56be997d6b
commit a2021ca326
4 changed files with 62 additions and 111 deletions

View File

@ -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<InheritanceDescriptor>,
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<PathBuf>,
}
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<T: std::fmt::Display, S: serde::Serializer>(
field: &Option<T>,
s: S,
) -> Result<S::Ok, S::Error> {
match field {
Some(field) => s.serialize_str(&field.to_string()),
None => s.serialize_none(),
}
}
impl TryFrom<Config> for MinisafeConfig {
impl TryFrom<Context> for MinisafeConfig {
type Error = &'static str;
fn try_from(cfg: Config) -> Result<Self, Self::Error> {
if cfg.main_descriptor.is_none() {
fn try_from(ctx: Context) -> Result<Self, Self::Error> {
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,
})
}
}

View File

@ -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<Message>) {
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<PathBuf, Error> {
pub async fn install(ctx: Context) -> Result<PathBuf, Error> {
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<PathBuf, Er
// create minisafed configuration file
let mut minisafed_config_path = datadir_path.clone();
minisafed_config_path.push(DaemonConfig::DEFAULT_FILE_NAME);
minisafed_config_path.push(DEFAULT_FILE_NAME);
let mut minisafed_config_file = std::fs::File::create(&minisafed_config_path)
.map_err(|e| Error::CannotCreateFile(e.to_string()))?;

View File

@ -12,7 +12,6 @@ use minisafe::{
use crate::{
hw::{list_hardware_wallets, HardwareWallet},
installer::{
config,
message::{self, Message},
step::{Context, Step},
view, Error,
@ -101,7 +100,7 @@ impl Step for DefineDescriptor {
Command::none()
}
fn apply(&mut self, _ctx: &mut Context, config: &mut config::Config) -> 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
}
}

View File

@ -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<BitcoindConfig>,
pub descriptor: Option<InheritanceDescriptor>,
pub data_dir: Option<PathBuf>,
}
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<PathBuf>) -> 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<Message> {
@ -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<Message> {
@ -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
}
}