diff --git a/src/context.rs b/src/context.rs index 7db8f7d56..5ad01c106 100644 --- a/src/context.rs +++ b/src/context.rs @@ -22,6 +22,7 @@ use crate::events::{Event, EventEmitter, EventType, Events}; use crate::key::{DcKey, SignedPublicKey}; use crate::login_param::LoginParam; use crate::message::{self, MessageState, MsgId}; +use crate::qr::Qr; use crate::quota::QuotaInfo; use crate::scheduler::Scheduler; use crate::sql::Sql; @@ -189,6 +190,10 @@ pub struct InnerContext { pub(crate) blobdir: PathBuf, pub(crate) sql: Sql, pub(crate) last_smeared_timestamp: RwLock, + /// The global "ongoing" process state. + /// + /// This is a global mutex-like state for operations which should be modal in the + /// clients. running_state: RwLock, /// Mutex to avoid generating the key for the user more than once. pub(crate) generating_key_mutex: Mutex<()>, @@ -228,6 +233,14 @@ pub struct InnerContext { /// If debug logging is enabled, this contains all neccesary information pub(crate) debug_logging: RwLock>, + + /// Qr code for currently running [`BackupProvider`]. + /// + /// This is only available if a backup export is currently running, it will also be + /// holding the ongoing process while running. + /// + /// [`BackupProvider`]: crate::imex::BackupProvider + pub(crate) export_provider: std::sync::Mutex>, } #[derive(Debug)] @@ -370,6 +383,7 @@ impl Context { last_full_folder_scan: Mutex::new(None), last_error: std::sync::RwLock::new("".to_string()), debug_logging: RwLock::new(None), + export_provider: std::sync::Mutex::new(None), }; let ctx = Context { @@ -563,6 +577,17 @@ impl Context { } } + /// Returns the QR-code of the currently running [`BackupProvider`]. + /// + /// [`BackupProvider`]: crate::imex::BackupProvider + pub fn backup_export_qr(&self) -> Option { + self.export_provider + .lock() + .expect("poisoned lock") + .as_ref() + .cloned() + } + /******************************************************************************* * UI chat/message related API ******************************************************************************/ diff --git a/src/imex/transfer.rs b/src/imex/transfer.rs index 24e2f6fd7..d345c94a8 100644 --- a/src/imex/transfer.rs +++ b/src/imex/transfer.rs @@ -118,7 +118,10 @@ impl BackupProvider { cancel_token, dbfile, )); - Ok(Self { handle, ticket }) + let slf = Self { handle, ticket }; + let qr = slf.qr(); + *context.export_provider.lock().expect("poisoned lock") = Some(qr); + Ok(slf) } /// Creates the provider task. @@ -128,7 +131,7 @@ impl BackupProvider { // Generate the token up front: we also use it to encrypt the database. let token = AuthToken::generate(); context.emit_event(SendProgress::Started.into()); - export_database(context, &dbfile, token.to_string()) + export_database(context, dbfile, token.to_string()) .await .context("Database export failed")?; context.emit_event(SendProgress::DatabaseExported.into()); @@ -171,7 +174,6 @@ impl BackupProvider { cancel_token: Receiver<()>, dbfile: PathBuf, ) -> Result<()> { - context.emit_event(SendProgress::ProviderListening.into()); let mut events = provider.subscribe(); let res = loop { tokio::select! { @@ -194,7 +196,6 @@ impl BackupProvider { provider.shutdown(); } Event::TransferAborted { .. } => { - context.emit_event(SendProgress::Failed.into()); provider.shutdown(); break Err(anyhow!("BackupSender transfer aborted")); } @@ -221,7 +222,15 @@ impl BackupProvider { if let Err(err) = fs::remove_file(&dbfile).await { error!(context, "Failed to remove database export: {err:#}"); } - context.emit_event(SendProgress::Completed.into()); + context + .export_provider + .lock() + .expect("poisoned lock") + .take(); + match &res { + Ok(_) => context.emit_event(SendProgress::Completed.into()), + Err(_) => context.emit_event(SendProgress::Failed.into()), + } context.free_ongoing().await; res }