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}