Skip to content

Commit 54aae9a

Browse files
committed
gui: integrate restore backup to Settings
1 parent 76b7826 commit 54aae9a

File tree

12 files changed

+157
-52
lines changed

12 files changed

+157
-52
lines changed

liana-gui/src/app/error.rs

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use lianad::config::ConfigError;
77
use crate::{
88
app::{settings::SettingsError, wallet::WalletError},
99
daemon::DaemonError,
10+
export,
1011
};
1112

1213
#[derive(Debug)]
@@ -18,6 +19,7 @@ pub enum Error {
1819
HardwareWallet(async_hwi::Error),
1920
Desc(LianaDescError),
2021
Spend(SpendCreationError),
22+
ImportExport(export::Error),
2123
}
2224

2325
impl std::fmt::Display for Error {
@@ -58,6 +60,7 @@ impl std::fmt::Display for Error {
5860
Self::Unexpected(e) => write!(f, "Unexpected error: {}", e),
5961
Self::HardwareWallet(e) => write!(f, "error: {}\nPlease check if the device is still connected and unlocked with the correct firmware open for the current network and no other application is accessing the device.", e),
6062
Self::Desc(e) => write!(f, "Liana descriptor error: {}", e),
63+
Self::ImportExport(e) => write!(f, "{e}"),
6164
}
6265
}
6366
}

liana-gui/src/app/state/export.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,9 @@ impl ExportModal {
9898
self.state = ImportExportState::Progress(p);
9999
}
100100
}
101-
Progress::Finished | Progress::Ended => self.state = ImportExportState::Ended,
101+
Progress::Finished | Progress::Ended => {
102+
self.state = ImportExportState::Ended;
103+
}
102104
Progress::Error(e) => {
103105
if let ImportExportType::ImportBackup(labels, aliases) =
104106
&self.import_export_type
@@ -131,6 +133,11 @@ impl ExportModal {
131133
}
132134
// TODO: forward Descriptor
133135
}
136+
Progress::UpdateAliases(map) => {
137+
return Task::perform(async {}, move |_| {
138+
ImportExportMessage::UpdateAliases(map.clone()).into()
139+
});
140+
}
134141
},
135142
ImportExportMessage::TimedOut => {
136143
self.stop(ImportExportState::TimedOut);
@@ -177,6 +184,7 @@ impl ExportModal {
177184
}
178185
}
179186
}
187+
ImportExportMessage::UpdateAliases(_) => { /* unexpected */ }
180188
}
181189
Task::none()
182190
}

liana-gui/src/app/state/settings/mod.rs

+20-15
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use iced::Task;
1010
use liana_ui::{component::form, widget::Element};
1111

1212
use bitcoind::BitcoindSettingsState;
13-
use wallet::WalletSettingsState;
13+
use wallet::{app_backup, WalletSettingsState};
1414

1515
use crate::{
1616
app::{
@@ -22,9 +22,8 @@ use crate::{
2222
wallet::Wallet,
2323
Config,
2424
},
25-
backup::Backup,
2625
daemon::{Daemon, DaemonBackend},
27-
export::{ImportExportMessage, ImportExportType},
26+
export::{self, ImportExportMessage, ImportExportType},
2827
};
2928

3029
use super::export::ExportModal;
@@ -224,6 +223,14 @@ impl State for ImportExportSettingsState {
224223
self.modal = None;
225224
}
226225
Message::View(view::Message::ImportExport(m)) => {
226+
if let ImportExportMessage::UpdateAliases(aliases) = m {
227+
let mut wallet = (*self.wallet).clone();
228+
wallet.keys_aliases = aliases;
229+
let wallet = Arc::new(wallet);
230+
return Task::perform(async {}, move |_| {
231+
Message::WalletUpdated(Ok(wallet.clone()))
232+
});
233+
}
227234
if let Some(modal) = self.modal.as_mut() {
228235
return modal.update(m);
229236
};
@@ -262,13 +269,7 @@ impl State for ImportExportSettingsState {
262269
let wallet = self.wallet.clone();
263270
let daemon = daemon.clone();
264271
return Task::perform(
265-
async move {
266-
let backup =
267-
Backup::from_app(datadir, network, config, wallet, daemon).await;
268-
let backup = backup.unwrap();
269-
serde_json::to_string_pretty(&backup).unwrap()
270-
// TODO: do not unwrap, return an error message instead
271-
},
272+
async move { app_backup(datadir, network, config, wallet, daemon).await },
272273
|s| {
273274
Message::View(view::Message::Settings(
274275
view::SettingsMessage::ExportBackup(s),
@@ -278,16 +279,20 @@ impl State for ImportExportSettingsState {
278279
}
279280
}
280281
Message::View(view::Message::Settings(view::SettingsMessage::ExportBackup(backup))) => {
282+
let backup = match backup {
283+
Ok(b) => b,
284+
Err(e) => {
285+
self.warning = Some(Error::ImportExport(export::Error::Backup(e)));
286+
return Task::none();
287+
}
288+
};
281289
let modal = ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
282290
launch!(self, modal);
283291
}
284292
Message::View(view::Message::Settings(view::SettingsMessage::ImportWallet)) => {
285-
// TODO:
286293
if self.modal.is_none() {
287-
let modal = ExportModal::new(
288-
Some(daemon),
289-
ImportExportType::Descriptor(self.wallet.main_descriptor.clone()),
290-
);
294+
let modal =
295+
ExportModal::new(Some(daemon), ImportExportType::ImportBackup(None, None));
291296
launch!(self, modal);
292297
}
293298
}

liana-gui/src/app/state/settings/wallet.rs

+21-8
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::{
2626
wallet::Wallet,
2727
Config,
2828
},
29-
backup::Backup,
29+
backup::{self, Backup},
3030
daemon::{Daemon, DaemonBackend},
3131
export::{ImportExportMessage, ImportExportType},
3232
hw::{HardwareWallet, HardwareWalletConfig, HardwareWallets},
@@ -230,13 +230,7 @@ impl State for WalletSettingsState {
230230
let wallet = self.wallet.clone();
231231
let daemon = daemon.clone();
232232
Task::perform(
233-
async move {
234-
let backup =
235-
Backup::from_app(datadir, network, config, wallet, daemon).await;
236-
let backup = backup.unwrap();
237-
serde_json::to_string_pretty(&backup).unwrap()
238-
// TODO: do not unwrap, return an error message instead
239-
},
233+
async move { app_backup(datadir, network, config, wallet, daemon).await },
240234
|s| {
241235
Message::View(view::Message::Settings(
242236
view::SettingsMessage::ExportBackup(s),
@@ -249,6 +243,14 @@ impl State for WalletSettingsState {
249243
}
250244
Message::View(view::Message::Settings(view::SettingsMessage::ExportBackup(backup))) => {
251245
if self.modal.is_none() {
246+
let backup = match backup {
247+
Ok(b) => b,
248+
Err(e) => {
249+
self.warning =
250+
Some(Error::ImportExport(crate::export::Error::Backup(e)));
251+
return Task::none();
252+
}
253+
};
252254
let modal =
253255
// ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
254256
ExportModal::new(Some(daemon), ImportExportType::ExportBackup(backup));
@@ -510,3 +512,14 @@ async fn update_keys_aliases(
510512

511513
Ok(Arc::new(wallet))
512514
}
515+
516+
pub async fn app_backup(
517+
datadir: PathBuf,
518+
network: Network,
519+
config: Arc<Config>,
520+
wallet: Arc<Wallet>,
521+
daemon: Arc<dyn Daemon + Sync + Send>,
522+
) -> Result<String, backup::Error> {
523+
let backup = Backup::from_app(datadir, network, config, wallet, daemon).await?;
524+
serde_json::to_string_pretty(&backup).map_err(|_| backup::Error::Json)
525+
}

liana-gui/src/app/view/message.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::{app::menu::Menu, export::ImportExportMessage, node::bitcoind::RpcAuthType};
1+
use crate::{app::menu::Menu, backup, export::ImportExportMessage, node::bitcoind::RpcAuthType};
22
use liana::miniscript::bitcoin::{bip32::Fingerprint, OutPoint};
33

44
#[derive(Debug, Clone)]
@@ -79,7 +79,7 @@ pub enum SettingsMessage {
7979
ExportTransactions,
8080
ExportLabels,
8181
ExportWallet,
82-
ExportBackup(String),
82+
ExportBackup(Result<String, backup::Error>),
8383
ImportWallet,
8484
AboutSection,
8585
RegisterWallet,

liana-gui/src/app/view/warning.rs

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ impl From<&Error> for WarningMessage {
4949
Error::HardwareWallet(_) => WarningMessage("Hardware wallet error".to_string()),
5050
Error::Desc(e) => WarningMessage(format!("Descriptor analysis error: '{}'.", e)),
5151
Error::Spend(e) => WarningMessage(format!("Spend creation error: '{}'.", e)),
52+
Error::ImportExport(e) => WarningMessage(format!("{e}")),
5253
}
5354
}
5455
}

liana-gui/src/backup.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -45,25 +45,32 @@ pub struct Backup {
4545
pub proprietary: serde_json::Map<String, serde_json::Value>,
4646
}
4747

48-
#[derive(Debug)]
48+
#[derive(Debug, Clone)]
4949
pub enum Error {
5050
DescriptorMissing,
5151
NotSingleWallet,
5252
Json,
5353
SettingsFromFile,
54-
Daemon(DaemonError),
54+
Daemon(String),
5555
TxTimeMissing,
5656
}
5757

5858
impl Display for Error {
5959
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60-
write!(f, "{self:?}")
60+
match self {
61+
Error::DescriptorMissing => write!(f, "Backup: descriptor missing"),
62+
Error::NotSingleWallet => write!(f, "Backup: Zero or several wallet"),
63+
Error::Json => write!(f, "Backup: json error"),
64+
Error::SettingsFromFile => write!(f, "Backup: fail to parse setting from file"),
65+
Error::Daemon(e) => write!(f, "Backup daemon error: {e}"),
66+
Error::TxTimeMissing => write!(f, "Backup: transaction block height missing"),
67+
}
6168
}
6269
}
6370

6471
impl From<DaemonError> for Error {
6572
fn from(value: DaemonError) -> Self {
66-
Error::Daemon(value)
73+
Error::Daemon(value.to_string())
6774
}
6875
}
6976

liana-gui/src/export.rs

+33-15
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::{
22
collections::{BTreeSet, HashMap},
3+
fmt::Display,
34
fs::{self, File},
45
io::{Read, Write},
56
path::PathBuf,
@@ -11,6 +12,7 @@ use std::{
1112
time,
1213
};
1314

15+
use async_hwi::bitbox::api::btc::Fingerprint;
1416
use chrono::{DateTime, Duration, Utc};
1517
use liana::{
1618
descriptors::LianaDescriptor,
@@ -32,7 +34,7 @@ use crate::{
3234
settings::{KeySetting, Settings},
3335
view,
3436
},
35-
backup::Backup,
37+
backup::{self, Backup},
3638
daemon::{
3739
model::{HistoryTransaction, Labelled},
3840
Daemon, DaemonBackend, DaemonError,
@@ -103,6 +105,7 @@ pub enum ImportExportMessage {
103105
Close,
104106
Overwrite,
105107
Ignore,
108+
UpdateAliases(HashMap<Fingerprint, String>),
106109
}
107110

108111
impl From<ImportExportMessage> for view::Message {
@@ -141,6 +144,30 @@ pub enum Error {
141144
BackupImport(String),
142145
LabelsConflict(SyncSender<bool>),
143146
KeyAliasesConflict(SyncSender<bool>),
147+
Backup(backup::Error),
148+
}
149+
150+
impl Display for Error {
151+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152+
match self {
153+
Error::Io(e) => write!(f, "ImportExport Io Error: {e}"),
154+
Error::HandleLost => write!(f, "ImportExport: subprocess handle lost"),
155+
Error::UnexpectedEnd => write!(f, "ImportExport: unexpected end of the process"),
156+
Error::JoinError(e) => write!(f, "ImportExport fail to handle.join(): {e} "),
157+
Error::ChannelLost => write!(f, "ImportExport: the channel have been closed"),
158+
Error::NoParentDir => write!(f, "ImportExport: there is no parent dir"),
159+
Error::Daemon(e) => write!(f, "ImportExport daemon error: {e}"),
160+
Error::TxTimeMissing => write!(f, "ImportExport: transaction block height missing"),
161+
Error::DaemonMissing => write!(f, "ImportExport: the daemon is missing"),
162+
Error::ParsePsbt => write!(f, "ImportExport: fail to parse PSBT"),
163+
Error::ParseDescriptor => write!(f, "ImportExport: fail to parse descriptor"),
164+
Error::Bip329Export(e) => write!(f, "Bip329Export: {e}"),
165+
Error::BackupImport(e) => write!(f, "BackupImport: {e}"),
166+
Error::Backup(e) => write!(f, "Backup: {e}"),
167+
Error::LabelsConflict(_) => write!(f, " "),
168+
Error::KeyAliasesConflict(_) => write!(f, " "),
169+
}
170+
}
144171
}
145172

146173
#[derive(Debug, Clone)]
@@ -213,6 +240,7 @@ pub enum Progress {
213240
None,
214241
Psbt(Psbt),
215242
Descriptor(LianaDescriptor),
243+
UpdateAliases(HashMap<Fingerprint, String>),
216244
}
217245

218246
pub struct Export {
@@ -698,18 +726,6 @@ pub async fn import_backup(
698726
return;
699727
}
700728

701-
// let labels = account.labels.as_ref().map(|l| l.clone().into_vec());
702-
// let txs = &account.transactions;
703-
// let psbts = &account.psbts;
704-
//
705-
// let mut count = 0usize;
706-
//
707-
// count += txs.len();
708-
// count += psbts.len();
709-
// if let Some(labels) = &labels {
710-
// count += labels.len() * 2;
711-
// }
712-
713729
// TODO: check if timestamp matches?
714730

715731
// check if labels can be imported w/o conflict only if `overwrite_label` == false
@@ -928,6 +944,7 @@ pub async fn import_backup(
928944
}
929945

930946
settings.wallets.get_mut(0).expect("already checked").keys = settings_aliases
947+
.clone()
931948
.into_iter()
932949
.map(|(k, v)| KeySetting {
933950
name: v,
@@ -940,11 +957,12 @@ pub async fn import_backup(
940957
Error::BackupImport("Fail to import keys aliases".into())
941958
);
942959
return;
960+
} else {
961+
// Update wallet state
962+
send_progress!(sender, UpdateAliases(settings_aliases));
943963
}
944964
}
945965

946-
// TODO: update local wallet state after run
947-
948966
send_progress!(sender, Progress(100.0));
949967
send_progress!(sender, Ended);
950968
}

liana-gui/src/installer/message.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::path::PathBuf;
66

77
use super::{context, Error};
88
use crate::{
9+
backup,
910
download::{DownloadError, Progress},
1011
export::ImportExportMessage,
1112
hw::HardwareWalletMessage,
@@ -46,7 +47,7 @@ pub enum Message {
4647
MnemonicWord(usize, String),
4748
ImportMnemonic(bool),
4849
BackupWallet,
49-
ExportWallet(String),
50+
ExportWallet(Result<String, backup::Error>),
5051
ImportExport(ImportExportMessage),
5152
}
5253

0 commit comments

Comments
 (0)