coven/file.rs
1//! Application file calls delegate to the composed sync file owner.
2use crate::*;
3
4impl CovenHandle {
5 /// The file's status as its record now stands (§17.6): one this device
6 /// uploads from local facts, one only on another device from its record,
7 /// and a stored one by a single-object status call. Network failures and
8 /// denied access are errors, not Missing.
9 pub async fn file_status(&self, file: &FileRef) -> Result<FileStatus, FileReadError> {
10 self.files.file_status(file).await
11 }
12 /// Prepares keeping stored files whole on this device regardless of the
13 /// cache budget, which pinned bytes don't count toward (§17.8): downloads what each lacks into a whole copy,
14 /// checked against its content hash, and pins nothing; a write commits
15 /// the result with `CovenWrite::pin`. A file only on one device, this
16 /// one included while it uploads, is refused with
17 /// `FileReadError::DeviceOnly`, and one whose record goes, or leaves its
18 /// stored bytes, while they download keeps nothing and fails with
19 /// `DbError::NoLongerStored`. A prepare that stops, dropped or ended by
20 /// a crash, keeps the bytes it downloaded of each file, apart from the
21 /// cache, and the next prepare of the file continues from them; the
22 /// app's unpin of the file ends them, and a prepare it ends fails with
23 /// `DbError::PinChanged`. Which files are downloading is in
24 /// `coven_downloading`, how far each has got on the download watch.
25 pub async fn prepare_pin(&self, files: &[FileRef]) -> Result<PreparedPin, FileReadError> {
26 self.files.prepare_pin(files).await
27 }
28 /// Prepares a pin and commits it in a write of its own.
29 pub async fn pin(&self, files: &[FileRef]) -> Result<(), FileReadError> {
30 let prepared = self.prepare_pin(files).await?;
31 self.write(move |write| write.pin(prepared)).await.map_err(FileReadError::from)
32 }
33 /// Verified cache coverage for these fixed references, in one snapshot.
34 pub async fn pin_progress(&self, files: Vec<FileRef>) -> CovenResult<PinProgress> {
35 self.database.pin_progress(files).await.map_err(CovenError::from)
36 }
37 /// The same pre-built cache query with the same fixed references.
38 pub fn subscribe_pin_progress(
39 &self,
40 files: Vec<FileRef>,
41 ) -> LiveQuery<PinProgress, CovenError> {
42 self.database.subscribe_pin_progress(files)
43 }
44 /// Remove the files' copies from this device, in a write of its own
45 /// (`CovenWrite::unpin`).
46 pub async fn unpin(&self, files: &[FileId]) -> CovenResult<()> {
47 let files = files.to_vec();
48 self.write(move |write| Ok(write.unpin(&files)?)).await
49 }
50 /// Whether each file is pinned, one answer per file in order, or `None`
51 /// for a file this device has no record of. The answer is whether
52 /// `coven_pins` lists it.
53 pub async fn files_pinned(&self, files: &[FileId]) -> CovenResult<Vec<Option<bool>>> {
54 self.database.files_pinned(files.to_vec()).await.map_err(CovenError::from)
55 }
56 /// The same internal query, live. To watch different files, drop this
57 /// query and subscribe with the new files.
58 pub fn subscribe_files_pinned(
59 &self,
60 files: &[FileId],
61 ) -> LiveQuery<Vec<Option<bool>>, CovenError> {
62 self.database.subscribe_files_pinned(files.to_vec())
63 }
64 /// Remove cache copies only, in a write of its own
65 /// (`CovenWrite::evict_file`).
66 pub async fn evict_file(&self, file: FileId) -> CovenResult<()> {
67 self.write(move |write| Ok(write.evict_file(file)?)).await
68 }
69 /// Clear a namespace's cache, in a write of its own
70 /// (`CovenWrite::clear_cache`).
71 pub async fn clear_cache(&self, namespace: &str) -> CovenResult<()> {
72 let namespace = namespace.to_owned();
73 self.write(move |write| Ok(write.clear_cache(&namespace)?)).await
74 }
75 /// Set and enforce a namespace's independent byte budget, in a write of
76 /// its own (`CovenWrite::set_cache_budget`).
77 pub async fn set_cache_budget(&self, namespace: &str, max_bytes: u64) -> CovenResult<()> {
78 let namespace = namespace.to_owned();
79 self.write(move |write| Ok(write.set_cache_budget(&namespace, max_bytes)?)).await
80 }
81 /// The namespace's budget, declared or since set.
82 pub async fn get_cache_budget(&self, namespace: &str) -> Result<u64, DbError> {
83 self.files.get_cache_budget(namespace).await
84 }
85}
86#[cfg(test)]
87#[path = "file_tests.rs"]
88mod tests;