| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
use std::path::PathBuf; |
| 8 |
|
| 9 |
use rusqlite::Connection; |
| 10 |
use synckit_client::{BlobPolicy, BlobRef, Result, SyncKitError}; |
| 11 |
|
| 12 |
use crate::state::DESKTOP_USER_ID; |
| 13 |
|
| 14 |
|
| 15 |
pub(crate) struct AttachmentBlobs { |
| 16 |
data_dir: PathBuf, |
| 17 |
user_id: String, |
| 18 |
} |
| 19 |
|
| 20 |
impl AttachmentBlobs { |
| 21 |
pub(crate) fn new(data_dir: PathBuf) -> Self { |
| 22 |
Self { |
| 23 |
data_dir, |
| 24 |
user_id: DESKTOP_USER_ID.to_string(), |
| 25 |
} |
| 26 |
} |
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
fn all_blobs(&self, conn: &Connection) -> Result<Vec<BlobRef>> { |
| 32 |
let mut stmt = conn |
| 33 |
.prepare("SELECT DISTINCT blob_hash, file_size FROM attachments WHERE user_id = ?1") |
| 34 |
.map_err(map_err)?; |
| 35 |
let rows = stmt |
| 36 |
.query_map([&self.user_id], |r| { |
| 37 |
let hash: String = r.get(0)?; |
| 38 |
let size: i64 = r.get(1)?; |
| 39 |
Ok(BlobRef { |
| 40 |
hash, |
| 41 |
ext: String::new(), |
| 42 |
size: size.max(0) as u64, |
| 43 |
}) |
| 44 |
}) |
| 45 |
.map_err(map_err)?; |
| 46 |
rows.collect::<rusqlite::Result<Vec<_>>>().map_err(map_err) |
| 47 |
} |
| 48 |
} |
| 49 |
|
| 50 |
#[allow( |
| 51 |
clippy::needless_pass_by_value, |
| 52 |
reason = "used as a `.map_err(map_err)` callback, which passes the error by value" |
| 53 |
)] |
| 54 |
fn map_err(e: rusqlite::Error) -> SyncKitError { |
| 55 |
SyncKitError::Internal(format!("attachment blob query: {e}")) |
| 56 |
} |
| 57 |
|
| 58 |
impl BlobPolicy for AttachmentBlobs { |
| 59 |
fn pending_uploads(&self, conn: &Connection) -> Result<Vec<BlobRef>> { |
| 60 |
self.all_blobs(conn) |
| 61 |
} |
| 62 |
|
| 63 |
fn pending_downloads(&self, conn: &Connection) -> Result<Vec<BlobRef>> { |
| 64 |
self.all_blobs(conn) |
| 65 |
} |
| 66 |
|
| 67 |
fn local_path(&self, blob: &BlobRef) -> PathBuf { |
| 68 |
crate::commands::attachment::blob_path(&self.data_dir, &blob.hash) |
| 69 |
} |
| 70 |
|
| 71 |
|
| 72 |
} |
| 73 |
|