From 1322d8c617342625d751d66e5e3c4cfe5849b69b Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Fri, 13 Mar 2020 20:49:01 +1000 Subject: [PATCH] make the collection optional --- proto/backend.proto | 1 + rslib/src/backend/mod.rs | 63 ++++++++++++++++++++++++++-------------- rslib/src/err.rs | 3 ++ 3 files changed, 46 insertions(+), 21 deletions(-) diff --git a/proto/backend.proto b/proto/backend.proto index 230158eb2..16eadd120 100644 --- a/proto/backend.proto +++ b/proto/backend.proto @@ -91,6 +91,7 @@ message BackendError { SyncError sync_error = 7; // user interrupted operation Empty interrupted = 8; + Empty collection_not_open = 9; } } diff --git a/rslib/src/backend/mod.rs b/rslib/src/backend/mod.rs index ca51c560f..b32f63fd7 100644 --- a/rslib/src/backend/mod.rs +++ b/rslib/src/backend/mod.rs @@ -32,7 +32,7 @@ mod dbproxy; pub type ProtoProgressCallback = Box) -> bool + Send>; pub struct Backend { - col: Arc>, + col: Arc>>, #[allow(dead_code)] col_path: PathBuf, media_folder: PathBuf, @@ -61,6 +61,7 @@ fn anki_error_to_proto_error(err: AnkiError, i18n: &I18n) -> pb::BackendError { } AnkiError::SyncError { kind, .. } => V::SyncError(pb::SyncError { kind: kind.into() }), AnkiError::Interrupted => V::Interrupted(Empty {}), + AnkiError::CollectionNotOpen => V::CollectionNotOpen(pb::Empty {}), }; pb::BackendError { @@ -156,7 +157,7 @@ impl Backend { log: Logger, ) -> Result { Ok(Backend { - col: Arc::new(Mutex::new(col)), + col: Arc::new(Mutex::new(Some(col))), col_path: col_path.into(), media_folder: media_folder.into(), media_db: media_db.into(), @@ -193,6 +194,22 @@ impl Backend { buf } + /// If collection is open, run the provided closure while holding + /// the mutex. + /// If collection is not open, return an error. + fn with_col(&self, func: F) -> Result + where + F: FnOnce(&Collection) -> Result, + { + func( + self.col + .lock() + .unwrap() + .as_ref() + .ok_or(AnkiError::CollectionNotOpen)?, + ) + } + fn run_command(&mut self, input: pb::BackendInput) -> pb::BackendOutput { let oval = if let Some(ival) = input.value { match self.run_command_inner(ival) { @@ -433,17 +450,20 @@ impl Backend { |progress: usize| self.fire_progress_callback(Progress::MediaCheck(progress as u32)); let mgr = MediaManager::new(&self.media_folder, &self.media_db)?; - self.col.lock().unwrap().transact(None, |ctx| { - let mut checker = MediaChecker::new(ctx, &mgr, callback); - let mut output = checker.check()?; - let report = checker.summarize_output(&mut output); + self.with_col(|col| { + col.transact(None, |ctx| { + let mut checker = MediaChecker::new(ctx, &mgr, callback); + let mut output = checker.check()?; - Ok(pb::MediaCheckOut { - unused: output.unused, - missing: output.missing, - report, - have_trash: output.trash_count > 0, + let report = checker.summarize_output(&mut output); + + Ok(pb::MediaCheckOut { + unused: output.unused, + missing: output.missing, + report, + have_trash: output.trash_count > 0, + }) }) }) } @@ -490,10 +510,12 @@ impl Backend { |progress: usize| self.fire_progress_callback(Progress::MediaCheck(progress as u32)); let mgr = MediaManager::new(&self.media_folder, &self.media_db)?; - self.col.lock().unwrap().transact(None, |ctx| { - let mut checker = MediaChecker::new(ctx, &mgr, callback); + self.with_col(|col| { + col.transact(None, |ctx| { + let mut checker = MediaChecker::new(ctx, &mgr, callback); - checker.empty_trash() + checker.empty_trash() + }) }) } @@ -502,18 +524,17 @@ impl Backend { |progress: usize| self.fire_progress_callback(Progress::MediaCheck(progress as u32)); let mgr = MediaManager::new(&self.media_folder, &self.media_db)?; - self.col.lock().unwrap().transact(None, |ctx| { - let mut checker = MediaChecker::new(ctx, &mgr, callback); + self.with_col(|col| { + col.transact(None, |ctx| { + let mut checker = MediaChecker::new(ctx, &mgr, callback); - checker.restore_trash() + checker.restore_trash() + }) }) } pub fn db_command(&self, input: &[u8]) -> Result { - self.col - .lock() - .unwrap() - .with_ctx(|ctx| db_command_bytes(&ctx.storage, input)) + self.with_col(|col| col.with_ctx(|ctx| db_command_bytes(&ctx.storage, input))) } } diff --git a/rslib/src/err.rs b/rslib/src/err.rs index 66e4bc66c..1ec149bc4 100644 --- a/rslib/src/err.rs +++ b/rslib/src/err.rs @@ -33,6 +33,9 @@ pub enum AnkiError { #[fail(display = "The user interrupted the operation.")] Interrupted, + + #[fail(display = "Operation requires an open collection.")] + CollectionNotOpen, } // error helpers