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
This commit is contained in:
edouard 2023-03-13 14:47:11 +01:00
parent 1d6a34e910
commit 9577e6a227
5 changed files with 85 additions and 50 deletions

View File

@ -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<PathBuf>,
/// Path to lianad_rpc socket file.
pub daemon_rpc_path: Option<PathBuf>,
/// log level, can be "info", "debug", "trace".
pub log_level: Option<String>,
/// 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,

View File

@ -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 =

View File

@ -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<Network, String>),
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<Ne
)
})?;
liana::config::Config::from_file(Some(cfg.daemon_config_path.clone())).map_err(|e| match e {
if let Some(daemon_config_path) = cfg.daemon_config_path {
liana::config::Config::from_file(Some(daemon_config_path.clone())).map_err(|e| match e {
ConfigError::FileNotFound
| ConfigError::DatadirNotFound => {
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<Ne
} else {
format!(
"Failed to read daemon configuration file in the directory: {}",
cfg.daemon_config_path.to_string_lossy()
daemon_config_path.to_string_lossy()
)
}
}
@ -205,6 +202,7 @@ async fn check_network_datadir(mut path: PathBuf, network: Network) -> Result<Ne
)
}
})?;
}
Ok(network)
}

View File

@ -41,7 +41,6 @@ pub struct Loader {
pub gui_config: GUIConfig,
pub daemon_started: bool,
daemon_config: Config,
step: Step,
}
@ -70,20 +69,22 @@ impl Loader {
pub fn new(
datadir_path: PathBuf,
gui_config: GUIConfig,
daemon_config: Config,
network: bitcoin::Network,
) -> (Self, Command<Message>) {
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<Element<'a, T>>>(
.into()
}
async fn connect(
socket_path: PathBuf,
_config: Config,
) -> Result<Arc<dyn Daemon + Sync + Send>, Error> {
async fn connect(socket_path: PathBuf) -> Result<Arc<dyn Daemon + Sync + Send>, Error> {
let client = client::jsonrpc::JsonRPCClient::new(socket_path);
let daemon = Lianad::new(client);

View File

@ -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<dyn Error>> {
}
[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)]