From c48c2af7a10c6f4ed3b0ac575b545ba81f68d7f9 Mon Sep 17 00:00:00 2001 From: Floris Bruynooghe Date: Thu, 16 Feb 2023 16:49:20 +0100 Subject: [PATCH] Allow retrieval of backup QR on context This enables being able to get the QR code without needing to have access to the BackupProvider itself. This is useful for the JSON-RPC server. --- src/context.rs | 25 +++++++++++++++++++++++++ src/imex/transfer.rs | 19 ++++++++++++++----- 2 files changed, 39 insertions(+), 5 deletions(-) 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 }