Skip to main content

max / audiofiles

5.6 KB · 183 lines History Blame Raw
1 //! `DirectBackend` content-addressed store access: importing files, resolving a
2 //! hash to its path/extension/original name, and removing samples or orphans.
3
4 use super::{
5 BackendResult, ConformTarget, DeviceProfileSummary, DirectBackend, ExportBackend, ExportItem,
6 NodeId, Path, PathBuf, StoreBackend, VfsId,
7 };
8
9 impl StoreBackend for DirectBackend {
10 // --- Store ---
11
12 fn import_file(&self, path: &Path) -> BackendResult<String> {
13 let db = self.db.lock();
14 Ok(self.store.import(path, &db)?)
15 }
16
17 fn sample_path(&self, hash: &str, ext: &str) -> BackendResult<PathBuf> {
18 let db = self.db.lock();
19 Ok(audiofiles_core::store::resolve_file_path(
20 &self.store,
21 &db,
22 hash,
23 ext,
24 )?)
25 }
26
27 fn sample_extension(&self, hash: &str) -> BackendResult<String> {
28 let db = self.db.lock();
29 Ok(audiofiles_core::store::sample_extension(&db, hash)?)
30 }
31
32 fn sample_original_name(&self, hash: &str) -> BackendResult<String> {
33 let db = self.db.lock();
34 Ok(audiofiles_core::store::sample_original_name(&db, hash)?)
35 }
36
37 fn remove_sample(&self, hash: &str) -> BackendResult<()> {
38 let db = self.db.lock();
39 Ok(self.store.remove(hash, &db)?)
40 }
41
42 fn remove_orphaned_samples(&self) -> BackendResult<usize> {
43 let db = self.db.lock();
44 Ok(self.store.remove_orphaned_samples(&db)?)
45 }
46
47 fn cleanup_orphans_local(&self) -> BackendResult<usize> {
48 // `remove_orphaned_samples` now suppresses sync triggers internally, so
49 // local orphan GC never pushes a destructive `samples` DELETE across
50 // devices. This wrapper exists only to name the user-facing gesture.
51 let db = self.db.lock();
52 Ok(self.store.remove_orphaned_samples(&db)?)
53 }
54
55 fn list_tombstoned(&self) -> BackendResult<Vec<audiofiles_core::store::TombstonedSample>> {
56 let db = self.db.lock();
57 Ok(audiofiles_core::store::tombstoned_samples(&db)?)
58 }
59
60 fn undelete_sample(&self, hash: &str) -> BackendResult<()> {
61 let db = self.db.lock();
62 audiofiles_core::store::undelete_sample(&db, hash)?;
63 Ok(())
64 }
65
66 fn purge_sample(&self, hash: &str) -> BackendResult<()> {
67 let db = self.db.lock();
68 Ok(self.store.remove(hash, &db)?)
69 }
70
71 fn sweep_expired_tombstones(&self) -> BackendResult<usize> {
72 let db = self.db.lock();
73 Ok(self.store.sweep_expired_tombstones(&db)?)
74 }
75
76 fn sample_source_path(&self, hash: &str) -> BackendResult<Option<String>> {
77 let db = self.db.lock();
78 Ok(audiofiles_core::store::sample_source_path(&db, hash)?)
79 }
80
81 fn relocate_sample(&self, hash: &str, new_path: &Path) -> BackendResult<()> {
82 let db = self.db.lock();
83 Ok(audiofiles_core::store::relocate_sample(
84 &self.store,
85 &db,
86 hash,
87 new_path,
88 )?)
89 }
90
91 fn check_vault_integrity(&self) -> BackendResult<(usize, usize)> {
92 let db = self.db.lock();
93 Ok(audiofiles_core::store::check_loose_files_integrity(&db)?)
94 }
95
96 fn purge_missing_loose_files(&self) -> BackendResult<usize> {
97 let db = self.db.lock();
98 Ok(audiofiles_core::store::purge_missing_loose_files(&db)?)
99 }
100
101 fn relocate_missing_loose_files(
102 &self,
103 search_root: &std::path::Path,
104 ) -> BackendResult<(usize, usize)> {
105 let db = self.db.lock();
106 Ok(audiofiles_core::store::relocate_missing_loose_files(
107 &db,
108 search_root,
109 )?)
110 }
111
112 fn start_loose_files_check(&self) -> BackendResult<()> {
113 self.loose_files_send(crate::loose_files_worker::LooseFilesCommand::CheckIntegrity)
114 }
115
116 fn start_loose_files_relocate(&self, search_root: &std::path::Path) -> BackendResult<()> {
117 self.loose_files_send(crate::loose_files_worker::LooseFilesCommand::Relocate(
118 search_root.to_path_buf(),
119 ))
120 }
121
122 fn start_loose_files_purge(&self) -> BackendResult<()> {
123 self.loose_files_send(crate::loose_files_worker::LooseFilesCommand::Purge)
124 }
125
126 fn start_store_verify(&self) -> BackendResult<()> {
127 self.loose_files_send(crate::loose_files_worker::LooseFilesCommand::VerifyStore)
128 }
129 }
130
131 impl ExportBackend for DirectBackend {
132 // --- Export ---
133
134 fn collect_export_items(
135 &self,
136 vfs_id: VfsId,
137 parent_id: Option<NodeId>,
138 ) -> BackendResult<Vec<ExportItem>> {
139 let db = self.db.lock();
140 Ok(audiofiles_core::export::collect_export_items(
141 &db, vfs_id, parent_id,
142 )?)
143 }
144
145 fn enrich_export_with_tags(&self, items: &mut [ExportItem]) -> BackendResult<()> {
146 let db = self.db.lock();
147 audiofiles_core::export::enrich_with_tags(&db, items);
148 Ok(())
149 }
150
151 // --- Device profiles ---
152
153 fn list_device_profiles(&self) -> BackendResult<Vec<DeviceProfileSummary>> {
154 #[cfg(feature = "device-profiles")]
155 {
156 Ok(self.plugin_registry.list())
157 }
158 #[cfg(not(feature = "device-profiles"))]
159 {
160 Ok(Vec::new())
161 }
162 }
163
164 fn device_conform_target(
165 &self,
166 profile_name: &str,
167 source_rate: u32,
168 ) -> BackendResult<Option<ConformTarget>> {
169 #[cfg(feature = "device-profiles")]
170 {
171 Ok(self
172 .plugin_registry
173 .get(profile_name)
174 .map(|plugin| ConformTarget::for_device(&plugin.profile, source_rate)))
175 }
176 #[cfg(not(feature = "device-profiles"))]
177 {
178 let _ = (profile_name, source_rate);
179 Ok(None)
180 }
181 }
182 }
183