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:
parent
1d6a34e910
commit
9577e6a227
@ -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,
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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)]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user