import: implement import from file for psbt & descriptor
This commit is contained in:
parent
2b9324993a
commit
158651ebe7
@ -11,7 +11,7 @@ use lianad::config::Config as DaemonConfig;
|
||||
use crate::{
|
||||
app::{cache::Cache, error::Error, view, wallet::Wallet},
|
||||
daemon::model::*,
|
||||
export::ExportMessage,
|
||||
export::ImportExportMessage,
|
||||
hw::HardwareWalletMessage,
|
||||
};
|
||||
|
||||
@ -47,5 +47,5 @@ pub enum Message {
|
||||
LabelsUpdated(Result<HashMap<String, Option<String>>, Error>),
|
||||
BroadcastModal(Result<HashSet<Txid>, Error>),
|
||||
RbfModal(Box<HistoryTransaction>, bool, Result<HashSet<Txid>, Error>),
|
||||
Export(ExportMessage),
|
||||
Export(ImportExportMessage),
|
||||
}
|
||||
|
||||
@ -13,40 +13,40 @@ use crate::{
|
||||
view::{self, export::export_modal},
|
||||
},
|
||||
daemon::Daemon,
|
||||
export::{self, get_path, ExportMessage, ExportProgress, ExportState, ExportType},
|
||||
export::{self, get_path, ImportExportMessage, ImportExportState, ImportExportType, Progress},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ExportModal {
|
||||
path: Option<PathBuf>,
|
||||
handle: Option<Arc<Mutex<JoinHandle<()>>>>,
|
||||
state: ExportState,
|
||||
state: ImportExportState,
|
||||
error: Option<export::Error>,
|
||||
daemon: Arc<dyn Daemon + Sync + Send>,
|
||||
export_type: ExportType,
|
||||
import_export_type: ImportExportType,
|
||||
}
|
||||
|
||||
impl ExportModal {
|
||||
#[allow(clippy::new_without_default)]
|
||||
pub fn new(daemon: Arc<dyn Daemon + Sync + Send>, export_type: ExportType) -> Self {
|
||||
pub fn new(daemon: Arc<dyn Daemon + Sync + Send>, export_type: ImportExportType) -> Self {
|
||||
Self {
|
||||
path: None,
|
||||
handle: None,
|
||||
state: ExportState::Init,
|
||||
state: ImportExportState::Init,
|
||||
error: None,
|
||||
daemon,
|
||||
export_type,
|
||||
import_export_type: export_type,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn default_filename(&self) -> String {
|
||||
match &self.export_type {
|
||||
ExportType::Transactions => {
|
||||
match &self.import_export_type {
|
||||
ImportExportType::Transactions => {
|
||||
let date = chrono::Local::now().format("%Y-%m-%dT%H-%M-%S");
|
||||
format!("liana-txs-{date}.csv")
|
||||
}
|
||||
ExportType::Psbt(_) => "psbt.psbt".into(),
|
||||
ExportType::Descriptor(descriptor) => {
|
||||
ImportExportType::ExportPsbt(_) => "psbt.psbt".into(),
|
||||
ImportExportType::Descriptor(descriptor) => {
|
||||
let checksum = descriptor
|
||||
.to_string()
|
||||
.split_once('#')
|
||||
@ -55,48 +55,64 @@ impl ExportModal {
|
||||
.to_string();
|
||||
format!("liana-{}.descriptor", checksum)
|
||||
}
|
||||
ImportExportType::ImportPsbt => "psbt.psbt".into(),
|
||||
ImportExportType::ImportDescriptor => "descriptor.descriptor".into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn launch(&self) -> Task<app::message::Message> {
|
||||
Task::perform(get_path(self.default_filename()), |m| {
|
||||
app::message::Message::View(view::Message::Export(ExportMessage::Path(m)))
|
||||
app::message::Message::View(view::Message::ImportExport(ImportExportMessage::Path(m)))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: ExportMessage) -> Task<app::message::Message> {
|
||||
pub fn update(&mut self, message: ImportExportMessage) -> Task<app::message::Message> {
|
||||
match message {
|
||||
ExportMessage::ExportProgress(m) => match m {
|
||||
ExportProgress::Started(handle) => {
|
||||
ImportExportMessage::Progress(m) => match m {
|
||||
Progress::Started(handle) => {
|
||||
self.handle = Some(handle);
|
||||
self.state = ExportState::Progress(0.0);
|
||||
self.state = ImportExportState::Progress(0.0);
|
||||
}
|
||||
ExportProgress::Progress(p) => {
|
||||
if let ExportState::Progress(_) = self.state {
|
||||
self.state = ExportState::Progress(p);
|
||||
Progress::Progress(p) => {
|
||||
if let ImportExportState::Progress(_) = self.state {
|
||||
self.state = ImportExportState::Progress(p);
|
||||
}
|
||||
}
|
||||
ExportProgress::Finished | ExportProgress::Ended => self.state = ExportState::Ended,
|
||||
ExportProgress::Error(e) => self.error = Some(e),
|
||||
ExportProgress::None => {}
|
||||
Progress::Finished | Progress::Ended => self.state = ImportExportState::Ended,
|
||||
Progress::Error(e) => self.error = Some(e),
|
||||
Progress::None => {}
|
||||
Progress::Psbt(_) => {
|
||||
if self.import_export_type == ImportExportType::ImportPsbt {
|
||||
self.state = ImportExportState::Ended;
|
||||
}
|
||||
// TODO: forward PSBT
|
||||
}
|
||||
Progress::Descriptor(_) => {
|
||||
if self.import_export_type == ImportExportType::ImportDescriptor {
|
||||
self.state = ImportExportState::Ended;
|
||||
}
|
||||
// TODO: forward Descriptor
|
||||
}
|
||||
},
|
||||
ExportMessage::TimedOut => {
|
||||
self.stop(ExportState::TimedOut);
|
||||
ImportExportMessage::TimedOut => {
|
||||
self.stop(ImportExportState::TimedOut);
|
||||
}
|
||||
ExportMessage::UserStop => {
|
||||
self.stop(ExportState::Aborted);
|
||||
ImportExportMessage::UserStop => {
|
||||
self.stop(ImportExportState::Aborted);
|
||||
}
|
||||
ExportMessage::Path(p) => {
|
||||
ImportExportMessage::Path(p) => {
|
||||
if let Some(path) = p {
|
||||
self.path = Some(path);
|
||||
self.start();
|
||||
} else {
|
||||
return Task::perform(async {}, |_| {
|
||||
app::message::Message::View(view::Message::Export(ExportMessage::Close))
|
||||
app::message::Message::View(view::Message::ImportExport(
|
||||
ImportExportMessage::Close,
|
||||
))
|
||||
});
|
||||
}
|
||||
}
|
||||
ExportMessage::Close | ExportMessage::Open => { /* unreachable */ }
|
||||
ImportExportMessage::Close | ImportExportMessage::Open => { /* unreachable */ }
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
@ -106,36 +122,36 @@ impl ExportModal {
|
||||
export_modal(&self.state, self.error.as_ref(), "Transactions"),
|
||||
);
|
||||
match self.state {
|
||||
ExportState::TimedOut
|
||||
| ExportState::Aborted
|
||||
| ExportState::Ended
|
||||
| ExportState::Closed => modal.on_blur(Some(view::Message::Close)),
|
||||
ImportExportState::TimedOut
|
||||
| ImportExportState::Aborted
|
||||
| ImportExportState::Ended
|
||||
| ImportExportState::Closed => modal.on_blur(Some(view::Message::Close)),
|
||||
_ => modal,
|
||||
}
|
||||
.into()
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
self.state = ExportState::Started;
|
||||
self.state = ImportExportState::Started;
|
||||
}
|
||||
|
||||
pub fn stop(&mut self, state: ExportState) {
|
||||
pub fn stop(&mut self, state: ImportExportState) {
|
||||
if let Some(handle) = self.handle.take() {
|
||||
handle.lock().expect("poisoned").abort();
|
||||
self.state = state;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn subscription(&self) -> Option<Subscription<export::ExportProgress>> {
|
||||
pub fn subscription(&self) -> Option<Subscription<export::Progress>> {
|
||||
if let Some(path) = &self.path {
|
||||
match &self.state {
|
||||
ExportState::Started | ExportState::Progress(_) => {
|
||||
ImportExportState::Started | ImportExportState::Progress(_) => {
|
||||
Some(iced::Subscription::run_with_id(
|
||||
"transactions",
|
||||
export::export_subscription(
|
||||
self.daemon.clone(),
|
||||
path.to_path_buf(),
|
||||
ExportType::Transactions,
|
||||
self.import_export_type.clone(),
|
||||
),
|
||||
))
|
||||
}
|
||||
|
||||
@ -28,7 +28,7 @@ use crate::{
|
||||
wallet::Wallet,
|
||||
},
|
||||
daemon::model::{self, LabelsLoader},
|
||||
export::{ExportMessage, ExportType},
|
||||
export::{ImportExportMessage, ImportExportType},
|
||||
};
|
||||
|
||||
use crate::daemon::{
|
||||
@ -266,18 +266,18 @@ impl State for TransactionsPanel {
|
||||
);
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Export(ExportMessage::Open)) => {
|
||||
Message::View(view::Message::ImportExport(ImportExportMessage::Open)) => {
|
||||
if let TransactionsModal::None = &self.modal {
|
||||
self.modal = TransactionsModal::Export(ExportModal::new(
|
||||
daemon,
|
||||
ExportType::Transactions,
|
||||
ImportExportType::Transactions,
|
||||
));
|
||||
if let TransactionsModal::Export(m) = &self.modal {
|
||||
return m.launch();
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::View(view::Message::Export(ExportMessage::Close)) => {
|
||||
Message::View(view::Message::ImportExport(ImportExportMessage::Close)) => {
|
||||
if let TransactionsModal::Export(_) = &self.modal {
|
||||
self.modal = TransactionsModal::None;
|
||||
}
|
||||
@ -286,7 +286,7 @@ impl State for TransactionsPanel {
|
||||
return match &mut self.modal {
|
||||
TransactionsModal::CreateRbf(modal) => modal.update(daemon, _cache, message),
|
||||
TransactionsModal::Export(modal) => {
|
||||
if let Message::View(view::Message::Export(m)) = msg {
|
||||
if let Message::View(view::Message::ImportExport(m)) = msg {
|
||||
modal.update(m.clone())
|
||||
} else {
|
||||
Task::none()
|
||||
@ -330,7 +330,9 @@ impl State for TransactionsPanel {
|
||||
if let TransactionsModal::Export(modal) = &self.modal {
|
||||
if let Some(sub) = modal.subscription() {
|
||||
return sub.map(|m| {
|
||||
Message::View(view::Message::Export(ExportMessage::ExportProgress(m)))
|
||||
Message::View(view::Message::ImportExport(ImportExportMessage::Progress(
|
||||
m,
|
||||
)))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,21 +11,21 @@ use liana_ui::{
|
||||
widget::Element,
|
||||
};
|
||||
|
||||
use crate::export::{Error, ExportMessage};
|
||||
use crate::{app::view::message::Message, export::ExportState};
|
||||
use crate::export::{Error, ImportExportMessage};
|
||||
use crate::{app::view::message::Message, export::ImportExportState};
|
||||
|
||||
/// Return the modal view for an export task
|
||||
pub fn export_modal<'a>(
|
||||
state: &ExportState,
|
||||
state: &ImportExportState,
|
||||
error: Option<&'a Error>,
|
||||
export_type: &str,
|
||||
) -> Element<'a, Message> {
|
||||
let button = match state {
|
||||
ExportState::Started | ExportState::Progress(_) => {
|
||||
Some(button::secondary(None, "Cancel").on_press(ExportMessage::UserStop.into()))
|
||||
ImportExportState::Started | ImportExportState::Progress(_) => {
|
||||
Some(button::secondary(None, "Cancel").on_press(ImportExportMessage::UserStop.into()))
|
||||
}
|
||||
ExportState::Ended | ExportState::TimedOut | ExportState::Aborted => {
|
||||
Some(button::secondary(None, "Close").on_press(ExportMessage::Close.into()))
|
||||
ImportExportState::Ended | ImportExportState::TimedOut | ImportExportState::Aborted => {
|
||||
Some(button::secondary(None, "Close").on_press(ImportExportMessage::Close.into()))
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
@ -33,26 +33,29 @@ pub fn export_modal<'a>(
|
||||
format!("{:?}", error)
|
||||
} else {
|
||||
match state {
|
||||
ExportState::Init => "".to_string(),
|
||||
ExportState::ChoosePath => {
|
||||
ImportExportState::Init => "".to_string(),
|
||||
ImportExportState::ChoosePath => {
|
||||
"Select the path you want to export in the popup window...".into()
|
||||
}
|
||||
ExportState::Path(_) => "".into(),
|
||||
ExportState::Started => "Starting export...".into(),
|
||||
ExportState::Progress(p) => format!("Progress: {}%", p.round()),
|
||||
ExportState::TimedOut => "Export failed: timeout".into(),
|
||||
ExportState::Aborted => "Export canceled".into(),
|
||||
ExportState::Ended => "Export successful!".into(),
|
||||
ExportState::Closed => "".into(),
|
||||
ImportExportState::Path(_) => "".into(),
|
||||
ImportExportState::Started => "Starting export...".into(),
|
||||
ImportExportState::Progress(p) => format!("Progress: {}%", p.round()),
|
||||
ImportExportState::TimedOut => "Export failed: timeout".into(),
|
||||
ImportExportState::Aborted => "Export canceled".into(),
|
||||
ImportExportState::Ended => "Export successful!".into(),
|
||||
ImportExportState::Closed => "".into(),
|
||||
}
|
||||
};
|
||||
let p = match state {
|
||||
ExportState::Init => 0.0,
|
||||
ExportState::ChoosePath | ExportState::Path(_) | ExportState::Started => 5.0,
|
||||
ExportState::Progress(p) => *p,
|
||||
ExportState::TimedOut | ExportState::Aborted | ExportState::Ended | ExportState::Closed => {
|
||||
100.0
|
||||
ImportExportState::Init => 0.0,
|
||||
ImportExportState::ChoosePath | ImportExportState::Path(_) | ImportExportState::Started => {
|
||||
5.0
|
||||
}
|
||||
ImportExportState::Progress(p) => *p,
|
||||
ImportExportState::TimedOut
|
||||
| ImportExportState::Aborted
|
||||
| ImportExportState::Ended
|
||||
| ImportExportState::Closed => 100.0,
|
||||
};
|
||||
let progress_bar_row = Row::new()
|
||||
.push(Space::with_width(30))
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::{app::menu::Menu, export::ExportMessage, node::bitcoind::RpcAuthType};
|
||||
use crate::{app::menu::Menu, export::ImportExportMessage, node::bitcoind::RpcAuthType};
|
||||
use liana::miniscript::bitcoin::{bip32::Fingerprint, OutPoint};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -19,7 +19,7 @@ pub enum Message {
|
||||
SelectHardwareWallet(usize),
|
||||
CreateRbf(CreateRbfMessage),
|
||||
ShowQrCode(usize),
|
||||
Export(ExportMessage),
|
||||
ImportExport(ImportExportMessage),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -25,7 +25,7 @@ use crate::{
|
||||
},
|
||||
},
|
||||
daemon::model::{HistoryTransaction, Txid},
|
||||
export::ExportMessage,
|
||||
export::ImportExportMessage,
|
||||
};
|
||||
|
||||
pub fn transactions_view<'a>(
|
||||
@ -44,7 +44,10 @@ pub fn transactions_view<'a>(
|
||||
Row::new()
|
||||
.push(Container::new(h3("Transactions")))
|
||||
.push(Space::with_width(Length::Fill))
|
||||
.push(button::secondary(None, "Export").on_press(ExportMessage::Open.into())),
|
||||
.push(
|
||||
button::secondary(None, "Export")
|
||||
.on_press(ImportExportMessage::Open.into()),
|
||||
),
|
||||
)
|
||||
.push(
|
||||
Column::new()
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
io::{Read, Write},
|
||||
path::PathBuf,
|
||||
str::FromStr,
|
||||
sync::{
|
||||
mpsc::{channel, Receiver, Sender},
|
||||
Arc, Mutex,
|
||||
@ -13,7 +14,7 @@ use std::{
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use liana::{
|
||||
descriptors::LianaDescriptor,
|
||||
miniscript::bitcoin::{Amount, Txid},
|
||||
miniscript::bitcoin::{Amount, Psbt, Txid},
|
||||
};
|
||||
use tokio::{
|
||||
task::{JoinError, JoinHandle},
|
||||
@ -33,26 +34,26 @@ use crate::{
|
||||
|
||||
macro_rules! send_error {
|
||||
($sender:ident, $error:ident) => {
|
||||
if let Err(e) = $sender.send(ExportProgress::Error(Error::$error)) {
|
||||
tracing::error!("ExportState::start() fail to send msg: {}", e);
|
||||
if let Err(e) = $sender.send(Progress::Error(Error::$error)) {
|
||||
tracing::error!("Import/Export fail to send msg: {}", e);
|
||||
}
|
||||
};
|
||||
($sender:ident, $error:expr) => {
|
||||
if let Err(e) = $sender.send(ExportProgress::Error($error)) {
|
||||
tracing::error!("ExportState::start() fail to send msg: {}", e);
|
||||
if let Err(e) = $sender.send(Progress::Error($error)) {
|
||||
tracing::error!("Import/Export fail to send msg: {}", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! send_progress {
|
||||
($sender:ident, $progress:ident) => {
|
||||
if let Err(e) = $sender.send(ExportProgress::$progress) {
|
||||
tracing::error!("ExportState::start() fail to send msg: {}", e);
|
||||
if let Err(e) = $sender.send(Progress::$progress) {
|
||||
tracing::error!("ImportExport fail to send msg: {}", e);
|
||||
}
|
||||
};
|
||||
($sender:ident, $progress:ident($val:expr)) => {
|
||||
if let Err(e) = $sender.send(ExportProgress::$progress($val)) {
|
||||
tracing::error!("ExportState::start() fail to send msg: {}", e);
|
||||
if let Err(e) = $sender.send(Progress::$progress($val)) {
|
||||
tracing::error!("ImportExport fail to send msg: {}", e);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -83,23 +84,23 @@ macro_rules! open_file {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExportMessage {
|
||||
pub enum ImportExportMessage {
|
||||
Open,
|
||||
ExportProgress(ExportProgress),
|
||||
Progress(Progress),
|
||||
TimedOut,
|
||||
UserStop,
|
||||
Path(Option<PathBuf>),
|
||||
Close,
|
||||
}
|
||||
|
||||
impl From<ExportMessage> for view::Message {
|
||||
fn from(value: ExportMessage) -> Self {
|
||||
Self::Export(value)
|
||||
impl From<ImportExportMessage> for view::Message {
|
||||
fn from(value: ImportExportMessage) -> Self {
|
||||
Self::ImportExport(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum ExportState {
|
||||
pub enum ImportExportState {
|
||||
Init,
|
||||
ChoosePath,
|
||||
Path(PathBuf),
|
||||
@ -121,13 +122,18 @@ pub enum Error {
|
||||
NoParentDir,
|
||||
Daemon(String),
|
||||
TxTimeMissing,
|
||||
DaemonMissing,
|
||||
ParsePsbt,
|
||||
ParseDescriptor,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum ExportType {
|
||||
pub enum ImportExportType {
|
||||
Transactions,
|
||||
Psbt(String),
|
||||
ExportPsbt(String),
|
||||
Descriptor(LianaDescriptor),
|
||||
ImportPsbt,
|
||||
ImportDescriptor,
|
||||
}
|
||||
|
||||
impl From<JoinError> for Error {
|
||||
@ -156,29 +162,31 @@ pub enum Status {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExportProgress {
|
||||
pub enum Progress {
|
||||
Started(Arc<Mutex<JoinHandle<()>>>),
|
||||
Progress(f32),
|
||||
Ended,
|
||||
Finished,
|
||||
Error(Error),
|
||||
None,
|
||||
Psbt(Psbt),
|
||||
Descriptor(LianaDescriptor),
|
||||
}
|
||||
|
||||
pub struct Export {
|
||||
pub receiver: Receiver<ExportProgress>,
|
||||
pub sender: Option<Sender<ExportProgress>>,
|
||||
pub receiver: Receiver<Progress>,
|
||||
pub sender: Option<Sender<Progress>>,
|
||||
pub handle: Option<Arc<Mutex<JoinHandle<()>>>>,
|
||||
pub daemon: Arc<dyn Daemon + Sync + Send>,
|
||||
pub daemon: Option<Arc<dyn Daemon + Sync + Send>>,
|
||||
pub path: Box<PathBuf>,
|
||||
pub export_type: ExportType,
|
||||
pub export_type: ImportExportType,
|
||||
}
|
||||
|
||||
impl Export {
|
||||
pub fn new(
|
||||
daemon: Arc<dyn Daemon + Sync + Send>,
|
||||
daemon: Option<Arc<dyn Daemon + Sync + Send>>,
|
||||
path: Box<PathBuf>,
|
||||
export_type: ExportType,
|
||||
export_type: ImportExportType,
|
||||
) -> Self {
|
||||
let (sender, receiver) = channel();
|
||||
Export {
|
||||
@ -192,15 +200,17 @@ impl Export {
|
||||
}
|
||||
|
||||
pub async fn export_logic(
|
||||
export_type: ExportType,
|
||||
sender: Sender<ExportProgress>,
|
||||
daemon: Arc<dyn Daemon + Sync + Send>,
|
||||
export_type: ImportExportType,
|
||||
sender: Sender<Progress>,
|
||||
daemon: Option<Arc<dyn Daemon + Sync + Send>>,
|
||||
path: PathBuf,
|
||||
) {
|
||||
match export_type {
|
||||
ExportType::Transactions => export_transactions(sender, daemon, path).await,
|
||||
ExportType::Psbt(psbt) => export_psbt(sender, path, psbt),
|
||||
ExportType::Descriptor(descriptor) => export_descriptor(sender, path, descriptor),
|
||||
ImportExportType::Transactions => export_transactions(sender, daemon, path).await,
|
||||
ImportExportType::ExportPsbt(psbt) => export_psbt(sender, path, psbt),
|
||||
ImportExportType::Descriptor(descriptor) => export_descriptor(sender, path, descriptor),
|
||||
ImportExportType::ImportPsbt => import_psbt(sender, path),
|
||||
ImportExportType::ImportDescriptor => import_descriptor(sender, path),
|
||||
};
|
||||
}
|
||||
|
||||
@ -238,10 +248,10 @@ impl Export {
|
||||
pub fn export_subscription(
|
||||
daemon: Arc<dyn Daemon + Sync + Send>,
|
||||
path: PathBuf,
|
||||
export_type: ExportType,
|
||||
) -> impl Stream<Item = ExportProgress> {
|
||||
export_type: ImportExportType,
|
||||
) -> impl Stream<Item = Progress> {
|
||||
iced::stream::channel(100, move |mut output| async move {
|
||||
let mut state = Export::new(daemon, Box::new(path), export_type);
|
||||
let mut state = Export::new(Some(daemon), Box::new(path), export_type);
|
||||
loop {
|
||||
match state.state() {
|
||||
Status::Init => {
|
||||
@ -269,7 +279,7 @@ pub fn export_subscription(
|
||||
let handle = match state.handle.take() {
|
||||
Some(h) => h,
|
||||
None => {
|
||||
if let Err(e) = output.send(ExportProgress::Error(Error::HandleLost)).await {
|
||||
if let Err(e) = output.send(Progress::Error(Error::HandleLost)).await {
|
||||
tracing::error!("export_subscription() fail to send message: {}", e);
|
||||
}
|
||||
continue;
|
||||
@ -278,9 +288,9 @@ pub fn export_subscription(
|
||||
let msg = {
|
||||
let h = handle.lock().expect("should not fail");
|
||||
if h.is_finished() {
|
||||
Some(ExportProgress::Finished)
|
||||
Some(Progress::Finished)
|
||||
} else if disconnected {
|
||||
Some(ExportProgress::Error(Error::ChannelLost))
|
||||
Some(Progress::Error(Error::ChannelLost))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -299,11 +309,18 @@ pub fn export_subscription(
|
||||
}
|
||||
|
||||
pub async fn export_transactions(
|
||||
sender: Sender<ExportProgress>,
|
||||
daemon: Arc<dyn Daemon + Sync + Send>,
|
||||
sender: Sender<Progress>,
|
||||
daemon: Option<Arc<dyn Daemon + Sync + Send>>,
|
||||
path: PathBuf,
|
||||
) {
|
||||
async move {
|
||||
let daemon = match daemon {
|
||||
Some(d) => d,
|
||||
None => {
|
||||
send_error!(sender, Error::DaemonMissing);
|
||||
return;
|
||||
}
|
||||
};
|
||||
let mut file = open_file!(path, sender);
|
||||
|
||||
let header = "Date,Label,Value,Fee,Txid,Block\n".to_string();
|
||||
@ -456,11 +473,7 @@ pub async fn export_transactions(
|
||||
.await;
|
||||
}
|
||||
|
||||
pub fn export_descriptor(
|
||||
sender: Sender<ExportProgress>,
|
||||
path: PathBuf,
|
||||
descriptor: LianaDescriptor,
|
||||
) {
|
||||
pub fn export_descriptor(sender: Sender<Progress>, path: PathBuf, descriptor: LianaDescriptor) {
|
||||
let mut file = open_file!(path, sender);
|
||||
|
||||
let descr_string = descriptor.to_string();
|
||||
@ -472,7 +485,7 @@ pub fn export_descriptor(
|
||||
send_progress!(sender, Ended);
|
||||
}
|
||||
|
||||
pub fn export_psbt(sender: Sender<ExportProgress>, path: PathBuf, psbt: String) {
|
||||
pub fn export_psbt(sender: Sender<Progress>, path: PathBuf, psbt: String) {
|
||||
let mut file = open_file!(path, sender);
|
||||
|
||||
if let Err(e) = file.write_all(psbt.as_bytes()) {
|
||||
@ -483,6 +496,48 @@ pub fn export_psbt(sender: Sender<ExportProgress>, path: PathBuf, psbt: String)
|
||||
send_progress!(sender, Ended);
|
||||
}
|
||||
|
||||
pub fn import_psbt(sender: Sender<Progress>, path: PathBuf) {
|
||||
let mut file = open_file!(path, sender);
|
||||
|
||||
let mut psbt_str = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut psbt_str) {
|
||||
send_error!(sender, e.into());
|
||||
return;
|
||||
}
|
||||
|
||||
let psbt = match Psbt::from_str(&psbt_str) {
|
||||
Ok(psbt) => psbt,
|
||||
Err(_) => {
|
||||
send_error!(sender, Error::ParsePsbt);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
send_progress!(sender, Progress(100.0));
|
||||
send_progress!(sender, Psbt(psbt));
|
||||
}
|
||||
|
||||
pub fn import_descriptor(sender: Sender<Progress>, path: PathBuf) {
|
||||
let mut file = open_file!(path, sender);
|
||||
|
||||
let mut descr_str = String::new();
|
||||
if let Err(e) = file.read_to_string(&mut descr_str) {
|
||||
send_error!(sender, e.into());
|
||||
return;
|
||||
}
|
||||
|
||||
let descriptor = match LianaDescriptor::from_str(&descr_str) {
|
||||
Ok(psbt) => psbt,
|
||||
Err(_) => {
|
||||
send_error!(sender, Error::ParseDescriptor);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
send_progress!(sender, Progress(100.0));
|
||||
send_progress!(sender, Descriptor(descriptor));
|
||||
}
|
||||
|
||||
pub async fn get_path(filename: String) -> Option<PathBuf> {
|
||||
rfd::AsyncFileDialog::new()
|
||||
.set_title("Choose a location to export...")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user