Skip to main content

cadmus_core/task/
import.rs

1//! Background task that imports library contents from disk.
2
3use std::sync::mpsc::Sender;
4
5use crate::db::Database;
6use crate::library::Library;
7use crate::library::importer;
8use crate::settings::Settings;
9use crate::task::{BackgroundTask, ShutdownSignal, TaskId};
10use crate::view::{Event, ID_FEEDER, ViewId};
11
12/// Runs an import for one library (or all libraries when `library_index` is `None`).
13///
14/// When `force` is `false` the import is incremental: files whose stored `mtime` and
15/// `file_size` have not changed are skipped without re-fingerprinting. When `force` is
16/// `true` every file is re-fingerprinted regardless.
17pub struct ImportTask {
18    database: Database,
19    settings: Settings,
20    /// Which library to import. `None` means all configured libraries.
21    library_index: Option<usize>,
22    /// When `true`, skip the mtime/size cache and re-fingerprint every file.
23    force: bool,
24}
25
26impl ImportTask {
27    pub fn new(
28        database: Database,
29        settings: Settings,
30        library_index: Option<usize>,
31        force: bool,
32    ) -> Self {
33        Self {
34            database,
35            settings,
36            library_index,
37            force,
38        }
39    }
40
41    #[cfg_attr(feature = "tracing", tracing::instrument(skip(hub, shutdown, self)))]
42    fn run_for_index(&self, index: usize, hub: &Sender<Event>, shutdown: &ShutdownSignal) {
43        let lib_settings = match self.settings.libraries.get(index) {
44            Some(s) => s,
45            None => {
46                tracing::warn!(
47                    library_index = index,
48                    "library index out of range, skipping"
49                );
50                return;
51            }
52        };
53
54        let library = match Library::new(&lib_settings.path, &self.database, &lib_settings.name) {
55            Ok(lib) => lib,
56            Err(e) => {
57                tracing::error!(error = %e, library_index = index, "failed to open library for import");
58                return;
59            }
60        };
61
62        let notif_id = ViewId::MessageNotif(ID_FEEDER.next());
63        importer::run(
64            &library.db,
65            library.library_id,
66            &library.home,
67            &self.settings.import,
68            self.force,
69            hub,
70            notif_id,
71            shutdown,
72        );
73    }
74}
75
76impl BackgroundTask for ImportTask {
77    fn id(&self) -> TaskId {
78        TaskId::Import
79    }
80
81    #[cfg_attr(feature = "tracing", tracing::instrument(skip_all))]
82    fn run(&mut self, hub: &Sender<Event>, shutdown: &ShutdownSignal) {
83        match self.library_index {
84            Some(index) => {
85                self.run_for_index(index, hub, shutdown);
86            }
87            None => {
88                for index in 0..self.settings.libraries.len() {
89                    if shutdown.should_stop() {
90                        return;
91                    }
92                    self.run_for_index(index, hub, shutdown);
93                }
94            }
95        }
96    }
97
98    fn finished_event(&self) -> Option<Event> {
99        Some(Event::ImportFinished {
100            library_index: self.library_index,
101        })
102    }
103}