coven/blob.rs
1//! Blob plumbing for sync.
2//!
3//! coven syncs opaque encrypted blobs referenced by DB rows. It owns the cloud
4//! layout (`{namespace}/{ab}/{cd}/{id}`) and encryption; the host decides which
5//! rows carry blobs, where their plaintext lives locally, and how each is
6//! scoped for encryption.
7
8use std::path::PathBuf;
9
10use crate::changeset::RowChange;
11
12/// Which key encrypts a blob.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum BlobScope {
15 /// The library master key.
16 Master,
17 /// A per-scope key derived from the master key (e.g. one key per item).
18 Derived(String),
19}
20
21/// A blob referenced by a changeset: its cloud identity plus the local file.
22#[derive(Debug, Clone)]
23pub struct BlobRef {
24 /// Cloud namespace, e.g. `"images"`. Becomes `{namespace}/{ab}/{cd}/{id}`.
25 pub namespace: String,
26 /// Blob id (typically the id of the blob-bearing row).
27 pub id: String,
28 /// Local plaintext file: the source on push, the destination on pull.
29 pub local_path: PathBuf,
30 /// Encryption scope for this blob.
31 pub scope: BlobScope,
32}
33
34/// Maps changeset row-changes to the blobs that must move with them.
35///
36/// The host knows which of its tables carry blobs and how to locate the local
37/// file. coven uploads referenced blobs before pushing a changeset and
38/// downloads them after applying an incoming one.
39pub trait BlobPlan: Send + Sync {
40 /// Blobs to upload before pushing an outgoing changeset.
41 fn blobs_to_push(&self, changes: &[RowChange]) -> Vec<BlobRef>;
42
43 /// Blobs to download after applying an incoming changeset.
44 fn blobs_to_pull(&self, changes: &[RowChange]) -> Vec<BlobRef>;
45}
46
47/// Notified after a blob upload completes, for host-specific bookkeeping
48/// (e.g. transitioning a record from "uploading" to "cloud-only").
49#[async_trait::async_trait]
50pub trait BlobUploadObserver: Send + Sync {
51 async fn on_blob_uploaded(&self, file_id: &str);
52}