fix gui: stop daemon gracefully
This commit is contained in:
parent
df7e575594
commit
a1c7166117
2
gui/Cargo.lock
generated
2
gui/Cargo.lock
generated
@ -1919,7 +1919,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "liana"
|
name = "liana"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = "git+https://github.com/wizardsardine/liana?branch=master#6c969aeacdde28a84f0a04060b280343a1e22afe"
|
source = "git+https://github.com/wizardsardine/liana?branch=master#05c9b580dba1933ffcc7efcc188dc75fdff211ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"backtrace",
|
"backtrace",
|
||||||
"bip39",
|
"bip39",
|
||||||
|
|||||||
@ -15,7 +15,7 @@ path = "src/main.rs"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-hwi = "0.0.10"
|
async-hwi = "0.0.10"
|
||||||
liana = { git = "https://github.com/wizardsardine/liana", branch = "master", default-features = false }
|
liana = { git = "https://github.com/wizardsardine/liana", branch = "master", default-features = false, features = ["nonblocking_shutdown"] }
|
||||||
liana_ui = { path = "ui" }
|
liana_ui = { path = "ui" }
|
||||||
backtrace = "0.3"
|
backtrace = "0.3"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
|
|||||||
@ -31,7 +31,7 @@ use state::{
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
app::{cache::Cache, error::Error, menu::Menu, wallet::Wallet},
|
app::{cache::Cache, error::Error, menu::Menu, wallet::Wallet},
|
||||||
daemon::Daemon,
|
daemon::{embedded::EmbeddedDaemon, Daemon},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
@ -113,11 +113,8 @@ impl App {
|
|||||||
pub fn stop(&mut self) {
|
pub fn stop(&mut self) {
|
||||||
info!("Close requested");
|
info!("Close requested");
|
||||||
if !self.daemon.is_external() {
|
if !self.daemon.is_external() {
|
||||||
info!("Stopping internal daemon...");
|
self.daemon.stop();
|
||||||
if let Some(d) = Arc::get_mut(&mut self.daemon) {
|
info!("Internal daemon stopped");
|
||||||
d.stop().expect("Daemon is internal");
|
|
||||||
info!("Internal daemon stopped");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,12 +168,9 @@ impl App {
|
|||||||
daemon_config_path: &PathBuf,
|
daemon_config_path: &PathBuf,
|
||||||
cfg: DaemonConfig,
|
cfg: DaemonConfig,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
loop {
|
self.daemon.stop();
|
||||||
if let Some(daemon) = Arc::get_mut(&mut self.daemon) {
|
let daemon = EmbeddedDaemon::start(cfg)?;
|
||||||
daemon.load_config(cfg)?;
|
self.daemon = Arc::new(daemon);
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut daemon_config_file = OpenOptions::new()
|
let mut daemon_config_file = OpenOptions::new()
|
||||||
.write(true)
|
.write(true)
|
||||||
|
|||||||
@ -58,9 +58,8 @@ impl<C: Client + Debug> Daemon for Lianad<C> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&mut self) -> Result<(), DaemonError> {
|
fn stop(&self) {
|
||||||
let _res: serde_json::value::Value = self.call("stop", Option::<Request>::None)?;
|
unreachable!("GUI should not ask external client to stop")
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::RwLock;
|
|
||||||
|
|
||||||
use super::{model::*, Daemon, DaemonError};
|
use super::{model::*, Daemon, DaemonError};
|
||||||
use liana::{
|
use liana::{
|
||||||
@ -10,22 +9,13 @@ use liana::{
|
|||||||
|
|
||||||
pub struct EmbeddedDaemon {
|
pub struct EmbeddedDaemon {
|
||||||
config: Config,
|
config: Config,
|
||||||
handle: Option<RwLock<DaemonHandle>>,
|
handle: DaemonHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EmbeddedDaemon {
|
impl EmbeddedDaemon {
|
||||||
pub fn new(config: Config) -> Self {
|
pub fn start(config: Config) -> Result<EmbeddedDaemon, DaemonError> {
|
||||||
Self {
|
let handle = DaemonHandle::start_default(config.clone()).map_err(DaemonError::Start)?;
|
||||||
config,
|
Ok(Self { handle, config })
|
||||||
handle: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(&mut self) -> Result<(), DaemonError> {
|
|
||||||
let handle =
|
|
||||||
DaemonHandle::start_default(self.config.clone()).map_err(DaemonError::Start)?;
|
|
||||||
self.handle = Some(RwLock::new(handle));
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,71 +30,32 @@ impl Daemon for EmbeddedDaemon {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_config(&mut self, cfg: Config) -> Result<(), DaemonError> {
|
|
||||||
if self.handle.is_none() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
|
|
||||||
let next = DaemonHandle::start_default(cfg).map_err(DaemonError::Start)?;
|
|
||||||
self.handle.take().unwrap().into_inner().unwrap().shutdown();
|
|
||||||
self.handle = Some(RwLock::new(next));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn config(&self) -> Option<&Config> {
|
fn config(&self) -> Option<&Config> {
|
||||||
Some(&self.config)
|
Some(&self.config)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&mut self) -> Result<(), DaemonError> {
|
fn stop(&self) {
|
||||||
if let Some(h) = self.handle.take() {
|
self.handle.trigger_shutdown();
|
||||||
let handle = h.into_inner().unwrap();
|
while !self.handle.shutdown_complete() {
|
||||||
handle.shutdown();
|
tracing::debug!("Waiting daemon to shutdown");
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
fn get_info(&self) -> Result<GetInfoResult, DaemonError> {
|
||||||
Ok(self
|
Ok(self.handle.control.get_info())
|
||||||
.handle
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
|
||||||
.get_info())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_new_address(&self) -> Result<GetAddressResult, DaemonError> {
|
fn get_new_address(&self) -> Result<GetAddressResult, DaemonError> {
|
||||||
Ok(self
|
Ok(self.handle.control.get_new_address())
|
||||||
.handle
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
|
||||||
.get_new_address())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_coins(&self) -> Result<ListCoinsResult, DaemonError> {
|
fn list_coins(&self) -> Result<ListCoinsResult, DaemonError> {
|
||||||
Ok(self
|
Ok(self.handle.control.list_coins())
|
||||||
.handle
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
|
||||||
.list_coins())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
fn list_spend_txs(&self) -> Result<ListSpendResult, DaemonError> {
|
||||||
Ok(self
|
Ok(self.handle.control.list_spend())
|
||||||
.handle
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
|
||||||
.list_spend())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_confirmed_txs(
|
fn list_confirmed_txs(
|
||||||
@ -115,23 +66,12 @@ impl Daemon for EmbeddedDaemon {
|
|||||||
) -> Result<ListTransactionsResult, DaemonError> {
|
) -> Result<ListTransactionsResult, DaemonError> {
|
||||||
Ok(self
|
Ok(self
|
||||||
.handle
|
.handle
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
.control
|
||||||
.list_confirmed_transactions(start, end, limit))
|
.list_confirmed_transactions(start, end, limit))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn list_txs(&self, txids: &[Txid]) -> Result<ListTransactionsResult, DaemonError> {
|
fn list_txs(&self, txids: &[Txid]) -> Result<ListTransactionsResult, DaemonError> {
|
||||||
Ok(self
|
Ok(self.handle.control.list_transactions(txids))
|
||||||
.handle
|
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
|
||||||
.list_transactions(txids))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_spend_tx(
|
fn create_spend_tx(
|
||||||
@ -141,10 +81,6 @@ impl Daemon for EmbeddedDaemon {
|
|||||||
feerate_vb: u64,
|
feerate_vb: u64,
|
||||||
) -> Result<CreateSpendResult, DaemonError> {
|
) -> Result<CreateSpendResult, DaemonError> {
|
||||||
self.handle
|
self.handle
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
.control
|
||||||
.create_spend(destinations, coins_outpoints, feerate_vb)
|
.create_spend(destinations, coins_outpoints, feerate_vb)
|
||||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||||
@ -152,32 +88,18 @@ impl Daemon for EmbeddedDaemon {
|
|||||||
|
|
||||||
fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError> {
|
fn update_spend_tx(&self, psbt: &Psbt) -> Result<(), DaemonError> {
|
||||||
self.handle
|
self.handle
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
.control
|
||||||
.update_spend(psbt.clone())
|
.update_spend(psbt.clone())
|
||||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
fn delete_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||||
self.handle
|
self.handle.control.delete_spend(txid);
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
|
||||||
.delete_spend(txid);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
fn broadcast_spend_tx(&self, txid: &Txid) -> Result<(), DaemonError> {
|
||||||
self.handle
|
self.handle
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
.control
|
||||||
.broadcast_spend(txid)
|
.broadcast_spend(txid)
|
||||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||||
@ -185,10 +107,6 @@ impl Daemon for EmbeddedDaemon {
|
|||||||
|
|
||||||
fn start_rescan(&self, t: u32) -> Result<(), DaemonError> {
|
fn start_rescan(&self, t: u32) -> Result<(), DaemonError> {
|
||||||
self.handle
|
self.handle
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
.control
|
||||||
.start_rescan(t)
|
.start_rescan(t)
|
||||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||||
@ -201,10 +119,6 @@ impl Daemon for EmbeddedDaemon {
|
|||||||
sequence: Option<u16>,
|
sequence: Option<u16>,
|
||||||
) -> Result<Psbt, DaemonError> {
|
) -> Result<Psbt, DaemonError> {
|
||||||
self.handle
|
self.handle
|
||||||
.as_ref()
|
|
||||||
.ok_or(DaemonError::NoAnswer)?
|
|
||||||
.read()
|
|
||||||
.unwrap()
|
|
||||||
.control
|
.control
|
||||||
.create_recovery(address, feerate_vb, sequence)
|
.create_recovery(address, feerate_vb, sequence)
|
||||||
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
.map_err(|e| DaemonError::Unexpected(e.to_string()))
|
||||||
|
|||||||
@ -43,11 +43,8 @@ impl std::fmt::Display for DaemonError {
|
|||||||
|
|
||||||
pub trait Daemon: Debug {
|
pub trait Daemon: Debug {
|
||||||
fn is_external(&self) -> bool;
|
fn is_external(&self) -> bool;
|
||||||
fn load_config(&mut self, _cfg: Config) -> Result<(), DaemonError> {
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
fn config(&self) -> Option<&Config>;
|
fn config(&self) -> Option<&Config>;
|
||||||
fn stop(&mut self) -> Result<(), DaemonError>;
|
fn stop(&self);
|
||||||
fn get_info(&self) -> Result<model::GetInfoResult, DaemonError>;
|
fn get_info(&self) -> Result<model::GetInfoResult, DaemonError>;
|
||||||
fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>;
|
fn get_new_address(&self) -> Result<model::GetAddressResult, DaemonError>;
|
||||||
fn list_coins(&self) -> Result<model::ListCoinsResult, DaemonError>;
|
fn list_coins(&self) -> Result<model::ListCoinsResult, DaemonError>;
|
||||||
|
|||||||
@ -171,11 +171,8 @@ impl Loader {
|
|||||||
if let Step::Syncing { daemon, .. } = &mut self.step {
|
if let Step::Syncing { daemon, .. } = &mut self.step {
|
||||||
if !daemon.is_external() {
|
if !daemon.is_external() {
|
||||||
info!("Stopping internal daemon...");
|
info!("Stopping internal daemon...");
|
||||||
if let Some(d) = Arc::get_mut(daemon) {
|
daemon.stop();
|
||||||
d.stop().expect("Daemon is internal");
|
info!("Internal daemon stopped");
|
||||||
info!("Internal daemon stopped");
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -335,8 +332,7 @@ pub async fn start_daemon(config_path: PathBuf) -> Result<Arc<dyn Daemon + Sync
|
|||||||
|
|
||||||
let config = Config::from_file(Some(config_path)).map_err(Error::Config)?;
|
let config = Config::from_file(Some(config_path)).map_err(Error::Config)?;
|
||||||
|
|
||||||
let mut daemon = EmbeddedDaemon::new(config);
|
let daemon = EmbeddedDaemon::start(config)?;
|
||||||
daemon.start()?;
|
|
||||||
|
|
||||||
Ok(Arc::new(daemon))
|
Ok(Arc::new(daemon))
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user