Skip to main content

CovenHandle

Struct CovenHandle 

Source
pub struct CovenHandle { /* private fields */ }
Expand description

The cipher a store’s app-data sealing runs under, resolved from custody.

A store whose custody unlocks None has no key to seal under or open with, which is SealError::Locked — the same discipline the sync engine’s cipher resolution keeps, where an opaque home with no established key refuses to start rather than inventing one.

Shared by CovenHandle and CovenReadHandle so both resolve the identical keyring the identical way; a payload one seals, the other opens. The handle over one coven store.

Open it once with Coven::builder, then call methods. Cheap to clone — every field is shared (an Arc, a Clone handle, or a reference-counted lock), so a clone drives the same retained owners as the original.

§Using the handle

The host builds the handle once at startup and then only calls methods on it — it never assembles coven’s internals by hand or hands them back to coven on every call. Rows go through the connection coven owns; blobs go through the handle’s read/store methods; sync is optional.

// Rows: run app SQL on the connection coven owns.
let note_count: i64 = handle
    .read(|sql| {
        sql.query_row("SELECT count(*) FROM notes", [], |row| row.get(0))
            .map_err(coven::CovenError::from)
    })
    .await?;

// Blobs: read an exact row version. coven resolves locality — the user's own
// file, its local store, the cache, or a cloud fetch — and returns plaintext.
let bytes: Vec<u8> = handle.read_blob(cover).await?;

// Sync is optional. Connect a provider, then drive it; a store with no
// cloud home never calls these and stays fully usable on-device.
handle.connect_sync().await?;
handle.sync_now();

Implementations§

Source§

impl CovenHandle

Source

pub async fn write<F, R>(&self, sql: F) -> CovenResult<WriteReceipt<R>>
where F: for<'context, 'connection> FnOnce(SqlContext<'context, 'connection>) -> CovenResult<R> + Send + 'static, R: Send + 'static,

Source

pub fn read<F, R>(&self, read: F) -> Read<'_, F>
where F: for<'connection> FnOnce(SqlReadContext<'connection>) -> CovenResult<R> + Send + 'static, R: Send + 'static,

Read one consistent snapshot when awaited. Attach process to compute a result on separate workers after releasing the connection.

Source

pub fn subscribe<F, R>(&self, query: F) -> LiveQuery<R>
where F: for<'connection> Fn(SqlReadContext<'connection>) -> CovenResult<R> + Send + Sync + 'static, R: Send + 'static,

Create a query that returns its initial value and runs again when a committed database change can affect it.

The query uses the same crate::SqlReadContext as read. Coven records the tables and columns SQLite reads, and narrows supported single-table primary-key predicates to their bound values. Other predicates retain safe table-and-column invalidation. Attach process to move result processing off the read connection. Only the final delivered value needs Clone and PartialEq.

Source

pub fn subscribe_reconfigurable<Request, F, R>( &self, initial_request: Request, query: F, ) -> ReconfigurableLiveQuery<Request, R>
where Request: Clone + PartialEq + Send + Sync + 'static, F: for<'connection> Fn(&Request, SqlReadContext<'connection>) -> CovenResult<R> + Send + Sync + 'static, R: Send + 'static,

Create a tracked query whose absolute request can be replaced while the subscription remains active. Attach process to process each result together with the request that produced it.

Source

pub async fn write_with_blobs<F, S, R>( &self, build: F, sql: S, ) -> CovenResult<WriteReceipt<R>>
where F: FnOnce(&mut WriteBatch) -> CovenResult<()> + Send + 'static, S: for<'context, 'connection> FnOnce(SqlContext<'context, 'connection>) -> CovenResult<R> + Send + 'static, R: Send + 'static,

Source

pub fn subscribe_sync_status(&self) -> Receiver<SyncLoopStatus>

Subscribe to the sync loop’s SyncLoopStatus stream. The channel is owned by this handle, not the loop, so the receiver keeps working across a reconnect and may be created before any provider is connected (it starts receiving once a loop runs). Infallible for that reason — there is no loop state to check.

The receiver immediately contains the current value. Intermediate values may be coalesced; Synchronized.row_changes is a refresh hint rather than a complete change stream.

Source

pub fn subscribe_eager_cache_fill_status( &self, ) -> Receiver<EagerCacheFillStatus>

Subscribe to the post-open CacheEager fill. Enrollment installs rows and returns without artwork; the connected library then reports discovery, bounded-cadence download progress, completion, cancellation, or failure.

Source

pub fn cancel_eager_cache_fill(&self)

Stop post-open CacheEager downloads without stopping cloud sync.

Source

pub async fn pending_writes(&self) -> Result<Vec<PendingWrite>, CovenError>

Writes that have shared rows and have not reached a published position.

Source

pub async fn blocked_writes(&self) -> Result<Vec<PendingWrite>, CovenError>

Writes stopped by a semantic publication fault and awaiting an explicit retry or discard decision.

Source

pub async fn retry_blocked_write( &self, write_id: &WriteId, ) -> Result<Vec<WriteId>, CovenError>

Requeue one blocked write for full production validation. A connected sync loop is woken after the durable transition.

Source

pub async fn retry_blocked_operation( &self, operation: BlockedOperationId, ) -> Result<(), RetryBlockedOperationError>

Hand one blocked operation back to the sync loop, whichever kind it is.

The host renders SyncLoopStatus::Blocked’s operations as one list with one button, so it retries them through one call; the id says which path the retry takes. Each kind revalidates from scratch, so an operation whose cause still stands simply blocks again.

Source

pub async fn discard_blocked_write( &self, write_id: &WriteId, ) -> Result<Vec<WriteId>, CovenError>

Atomically discard a blocked write and reverse every later unpublished shared write whose working-row state depends on it.

Source

pub async fn write_status( &self, write_id: &WriteId, ) -> Result<WriteStatus, CovenError>

Read the current durable status of one write.

Source

pub async fn subscribe_write_status( &self, write_id: &WriteId, ) -> Result<Receiver<WriteStatus>, CovenError>

Subscribe to one write’s current durable status. The initial value is reconstructed from SQLite before the receiver is returned.

Source

pub async fn connect_sync(&self) -> Result<(), SyncError>

Build the connected cloud storage, start its sync loop, and install the connection. If the cloud home fails to build, no connection is installed.

The at-rest cipher is resolved from the handle’s custody per start: an opaque home unlocks the master keyring (failing with SyncError::MasterKeyNotEstablished if none is established), a browsable one never consults custody. Reconnecting a provider replaces the cloud home and loop while retaining the Store database and clock.

Source

pub async fn probe_cloud_home(&self, config: &Config) -> Result<(), SyncError>

Build and probe the cloud home described by config without installing it as this handle’s sync connection. Hosts use this to validate proposed provider settings before committing them to their config source.

Source

pub async fn setup_s3_cloud_home( &self, cloud_home: CloudHomeConfig, access_key: String, secret_key: String, ) -> Result<ConnectedCloudHome, CloudHomeSetupError>

Connect a new S3 cloud home and commit its credentials and any generated opaque-home master key only after the replacement connection is ready.

Source

pub async fn setup_cloudkit_cloud_home( &self, cloud_home: CloudHomeConfig, cloudkit_ops: Arc<dyn CloudKitOps>, ) -> Result<ConnectedCloudHome, CloudHomeSetupError>

Connect a new CloudKit cloud home and commit any generated opaque-home master key only after the replacement connection is ready.

Source

pub async fn setup_oauth_cloud_home( &self, cloud_home: CloudHomeConfig, cancel: Receiver<bool>, ) -> Result<ConnectedCloudHome, CloudHomeSetupError>

Authorize and connect a new Google Drive, Dropbox, or OneDrive home. Tokens remain proposed until the replacement connection is ready.

Source

pub fn cloud_home_key_state( &self, storage: HomeStorage, ) -> Result<CloudHomeKeyState, KeyError>

Whether a home with this storage policy needs and can unlock its key.

Source

pub async fn unlock_cloud_home( &self, serialized_master_key: &str, ) -> Result<ConnectedCloudHome, CloudHomeUnlockError>

Import the master key for this returning opaque cloud home, verify it against the signed Store root, and connect without retaining a rejected key.

Source

pub async fn connect_sync_with_cloudkit( &self, cloudkit_ops: Arc<dyn CloudKitOps>, ) -> Result<(), SyncError>

Source

pub fn connect_sync_with_test_home( &self, home: Arc<dyn ExactCloudHome>, cipher: CloudCipher, ) -> impl Future<Output = Result<(), CloudHomeSetupError>> + Send + '_

Test-only: connect a started sync loop over an injected ExactCloudHome instead of one built from crate::Config, so a host’s integration tests drive the real make-Remote / make-Local / upload-drain and read paths over a mock cloud with no live provider.

The test counterpart of connect_sync: it builds storage over home/cipher, prepares the configured home’s master key, starts the loop, and commits a newly generated key and the connection together only after startup succeeds. The explicit cipher protects the injected storage; the master key separately protects Store routing data.

The read path needs no separate hook: blob_storage serves reads from the connected loop’s own CloudSyncConnection, which here wraps the injected home, so read_blob / pin resolve a Remote miss against the same test home the drain writes to.

Source

pub async fn setup_cloud_home_with_test_home( &self, cloud_home: CloudHomeConfig, home: Arc<dyn ExactCloudHome>, credentials: Option<CloudHomeCredentials>, ) -> Result<ConnectedCloudHome, CloudHomeSetupError>

Test-only: atomically set up a proposed cloud home over an injected provider while exercising the production key and connection transaction.

Source

pub async fn unlock_cloud_home_with_test_home( &self, serialized_master_key: &str, home: Arc<dyn ExactCloudHome>, ) -> Result<ConnectedCloudHome, CloudHomeUnlockError>

Test-only: unlock a returning opaque home over an injected provider while exercising the production key-and-connection transaction.

Source

pub fn connect_sync_with_test_home_caller_driven( &self, home: Arc<dyn ExactCloudHome>, cipher: CloudCipher, ) -> impl Future<Output = Result<(), CloudHomeSetupError>> + Send + '_

Test-only: connect over an injected ExactCloudHome exactly as connect_sync_with_test_home does, but start no background loop — the caller drives sync itself.

The loop-started connect and an explicit drain_uploads are two drainers of one queue. They take turns rather than overlap, so whichever runs second drains only what the first left — a host asserting on its own drain’s count reads that as “nothing was queued” and fails intermittently. Here no cycle exists to share the queue with: the host’s drain_uploads is the only drain, its count is the whole truth, and is_syncing stays false for the connection’s whole life.

Everything a connected store can do is available — make_remote, make_local, the drain, membership — because none of it needs the loop thread. Circle writes are the exception: they are dispatched to that thread, so they refuse with CircleError::LoopNotRunning here.

Source

pub async fn connect_sync_with_test_home_custody( &self, home: Arc<dyn ExactCloudHome>, ) -> Result<(), SyncError>

Test-only: connect over an injected ExactCloudHome while resolving the at-rest cipher from custody the way production connect_sync does, instead of taking an explicit cipher like connect_sync_with_test_home.

Where that method prepares a missing master key as part of its connection transaction, this requires an existing key and drives the connection path used by production, which unlocks the master keyring through the store’s custody exactly as start_sync would — so a test can establish a key, connect over a mock home, and prove the traffic is sealed under that key. An opaque home with no key established fails SyncError::MasterKeyNotEstablished before the loop starts.

Source

pub async fn start_sync(&self) -> Result<(), SyncError>

Start (or restart) the sync loop of the installed connection. A no-op when no provider is connected — a home-less store has nothing to start. Errors if the connected cloud home fails to build.

Source

pub fn stop_sync(&self)

Stop the sync loop after the in-flight cycle while keeping the provider connected so start_sync can resume it. A no-op when no provider is connected.

The material a running loop resolved from custody (the master keyring, the device signing identity) is cached only inside that loop for as long as it runs — nowhere else in the handle — and this is where it is purged. A subsequent start_sync/ connect_sync re-resolves fresh from whatever custody now serves, so a host’s lock flow that stops sync as part of locking, then later reconnects, never resumes on stale material.

Source

pub fn disconnect_sync(&self)

Disconnect the provider entirely: stop the loop and drop the connection. The store becomes home-less until the next connect_sync.

Carries the same purge as stop_sync, so nothing about the previous connection — including which custody it resolved material from — survives into the next connect.

Source

pub async fn disconnect_cloud_home(&self) -> Result<(), SyncError>

Disconnect the configured cloud home and remove its provider credentials. If credential removal fails, the installed connection is preserved.

Source

pub fn sync_now(&self)

Wake the sync loop to run a cycle now rather than at the next idle tick. A no-op when no provider is connected.

Source

pub fn is_syncing(&self) -> bool

Whether the sync loop is running. false for a home-less store.

Source

pub fn is_connected(&self) -> bool

Whether a provider connection is installed. Distinct from is_syncing, which additionally requires the loop to be running: this is the predicate a host uses for “has a cloud home” without the loop-ready condition.

Source

pub async fn import_master_key( &self, serialized: &str, ) -> Result<(), MasterKeyError>

Import a serialized master keyring a host already holds and establish it under the handle’s custody, replacing whatever custody already holds.

Source

pub async fn forget_master_key(&self) -> Result<(), SyncError>

Remove the master key from custody and disconnect any operation retaining its unlocked value. If custody cannot remove the key, the connection is preserved and the error is returned.

Source

pub fn initialize_identity(&self) -> Result<String, IdentityError>

Generate this store’s signing identity and establish it under the handle’s identity custody. Errors with IdentityError::AlreadyEstablished if custody already unlocks one — coven never generates over an existing identity. This is the identity counterpart of cloud-home setup’s master-key transaction for a store a host is creating fresh (not joining or restoring, which each establish their own identity as part of what they do). Returns the established public key, hex-encoded.

Source

pub fn transfer_limits(&self) -> TransferLimits

Set a host’s own store-scoped secret — an API token, a service credential — under the same platform keyring, and the same access policy, as coven’s own key material. name identifies the secret within the store; coven owns the account rendering and the entry’s protection class. KeyError::InvalidSecretName if name collides with one of coven’s own reserved slot names, is empty, or contains :. The concurrent blob-transfer limits in force: how many uploads an upload-drain pass runs at once and how many downloads a pin fetches at once.

Source

pub fn set_transfer_limits(&self, limits: TransferLimits)

Replace the transfer limits while the store is open. Every later upload-drain pass and pin call runs under the new limits; a pass already running keeps the limit it admitted under. The builder’s max_concurrent_uploads / max_concurrent_downloads set the initial values.

Source

pub fn set_host_secret(&self, name: &str, value: &str) -> Result<(), KeyError>

Source

pub fn host_secret(&self, name: &str) -> Result<Option<String>, KeyError>

Read a host secret set by set_host_secret, None if never set. A present-but-empty entry is corrupt, not absent — the same discipline coven’s own key reads apply.

Source

pub fn delete_host_secret(&self, name: &str) -> Result<(), KeyError>

Remove a host secret. Ok whether or not one was set.

Source

pub fn seal_app_data( &self, plaintext: &[u8], aad: &[u8], ) -> Result<Vec<u8>, SealError>

Seal plaintext under the store’s current master-key generation, for a host to store in its own rows — a password entry’s payload, an API token. coven’s at-rest encryption is cloud-side; the local database is plaintext SQLite, so a host with a secret to keep in a row seals it here first.

The output records the generation it was sealed under, so it stays openable after any number of key rotations. aad binds the ciphertext to its context — the owning row’s primary key, say — and open_app_data with a different aad fails, so a payload moved to another row does not silently open there.

SealError::Locked if the store has no established master key, the same gate connect_sync applies before it seals cloud traffic.

Source

pub fn open_app_data( &self, sealed: &[u8], aad: &[u8], ) -> Result<Vec<u8>, SealError>

Open a payload seal_app_data produced, under whichever generation it names — a rotated keyring still opens everything it sealed before rotating.

SealError::Locked if the store is locked; a wrong aad, a tampered payload, an unreadable version, or a generation this store’s keyring lacks each surface their own typed error.

Source

pub async fn row_blob_ref( &self, table: &str, row_id: &str, ) -> Result<RowBlobRef, DbError>

Capture the exact current blob-bearing row version. Blob operations use this row-bound value so a later row replacement cannot redirect a read.

Source

pub async fn read_blob( &self, blob: &RowBlobRef, ) -> Result<Vec<u8>, BlobCacheError>

Read a blob’s whole plaintext through coven’s locality-aware read: served from the user’s file (Local user-provided), coven’s local store (Local host-provided), the pinned/evictable cache on a Remote hit, or fetched from the cloud (into the cache) on a Remote miss. The host passes the RowBlobRef captured from row_blob_ref; coven holds the database, directory, and storage.

Source

pub async fn materialize_row_blob( &self, blob: &RowBlobRef, ) -> Result<(), BlobCacheError>

Ensure the exact current row blob plaintext is durable on this device. Remote blobs materialize into their locator-keyed cache path; Local and pending-remote blobs exact-verify their authoritative local source.

Source

pub async fn open_blob_stream( &self, blob: &RowBlobRef, ) -> Result<BlobStream, BlobCacheError>

Open an exact row blob’s plaintext for ranged reading, for streaming or seeking without loading the whole file. The ranged sibling of read_blob, which stays the one-shot whole read.

Opening resolves the blob’s locality, proves the plaintext’s size and content hash against the row, and holds the open file; every BlobStream::read_at then costs only the bytes it returns. Hold the stream for as long as the host is reading that blob — a stream per opened file, not per range — since re-opening re-proves the whole blob.

Source

pub async fn pin(&self, blobs: &[RowBlobRef]) -> Result<(), BlobCacheError>

Pin a Remote blob set for offline: coven fetches each into the protected cache (storage/pinned/) — from the evictable cache if already there, else the cloud — exempt from the size budget. Idempotent.

Source

pub async fn unpin(&self, blobs: &[RowBlobRef]) -> Result<(), BlobCacheError>

Unpin a Remote blob set: coven moves each from storage/pinned/ to the evictable storage/cache/ (still readable, now droppable). No cloud read.

Source

pub fn blob_cloud_key(&self, blob: &BlobRef) -> Result<String, StorageError>

The cloud object key a blob’s bytes live at, derived under the connected home’s path scheme (Hashed{namespace}/{ab}/{cd}/{id}, Plain{namespace}/{cloud_path}).

Read-only: coven owns this derivation and every operation that needs a key derives its own (a delete resolves it from the stored ref), so nothing a host calls takes one back. It exists so a host can observe the key coven would use — asserting an upload landed where a read looks for it, or naming an object in a diagnostic — without reimplementing the layout and drifting from it.

A Plain home whose cloud_path is absent, or does not name the blob it carries, is a surfaced error — see CloudSyncConnection::blob_key.

Source

pub async fn is_pinned( &self, blobs: &[RowBlobRef], ) -> Result<bool, BlobCacheError>

Whether every blob in blobs is pinned for offline — present in coven’s kept cache folder (storage/pinned/). The host answers “is this release kept offline” through this instead of stat-ing coven’s cache layout itself. An empty set is vacuously pinned. A blob not pinned (in the evictable cache or absent) makes the whole set unpinned; an existence-check failure is surfaced, never read as “not pinned”.

Source

pub async fn rows_pinned( &self, table: &str, row_ids: Vec<String>, ) -> Result<Vec<Option<bool>>, BlobCacheError>

Whether each of table’s row_ids is pinned for offline, one answer per id in the order given. None where an id names no live blob-bearing row.

is_pinned answers over blobs that together make up one thing — every blob of a release, pinned and unpinned together. This answers for many independent rows at once: a host drawing a “kept offline” marker per row of a page resolves and answers the whole page in one call, instead of a row_blob_ref and an is_pinned per row.

A row whose blob has no committed cloud object — one still Local, or one whose upload has not landed — has no kept copy to hold and reads as not pinned. An existence-check failure is still surfaced, never read as “not pinned”.

Source

pub async fn evict_blob(&self, blob: &RowBlobRef) -> Result<(), BlobCacheError>

Remove one Remote blob’s re-fetchable on-device cache copies from both storage/pinned/ and storage/cache/. This never touches the local store, whose bytes may be the only usable copy owned by an unpublished write. It does not delete the cloud blob or its carrying row; a later read can fetch the bytes again.

Source

pub async fn make_remote( &self, root_table: &str, root_id: &str, root_label: &str, pin: bool, refs: Vec<RowBlobRef>, ) -> Result<(), MakeRemoteError>

Make (root_table, root_id) Remote (Local → Remote): enqueue an upload per user-provided blob from its external file and record the make_remote intent, then return. The drain uploads each and flips the gate true on the last; the gate flip re-emits the subtree and the cycle’s inline push uploads host-provided blobs. pin keeps the uploaded blobs in the cache as pinned offline copies. Errors with MakeRemoteError::SyncNotReady when no provider is connected.

refs is the root’s complete current blob set in the order the host wants uploads admitted. coven validates the set atomically before enqueueing it. root_label is what the host calls this root, snapshotted onto the queue rows and the intent. The queue outlives the root row on purpose — a cancelled or deleted root still has cloud objects to unwind — so an entry that had to read the row to name itself could not be rendered at exactly the moment a person most needs to see it.

Source

pub async fn make_remote_batch( &self, root_table: &str, roots: Vec<MakeRemoteRoot>, pin: bool, ) -> Result<(), MakeRemoteError>

Source

pub async fn cancel_make_remote( &self, root_table: &str, root_id: &str, ) -> Result<(), MakeRemoteError>

Cancel an in-flight make_remote of (root_table, root_id): clear its intent and pending uploads and tombstone any blob already in the cloud. The gate never flips, so the root stays Local. Errors with MakeRemoteError::SyncNotReady when no provider is connected.

Source

pub async fn make_local( &self, root_table: &str, root_id: &str, dest: &HashMap<String, PathBuf>, cancel: &Receiver<bool>, ) -> Result<(), MakeLocalError>

Make (root_table, root_id) Local (Remote → Local): bring each blob back to a local file durability-first — a user-provided blob to the path named in dest (blob id → destination path), a host-provided blob to coven’s local store (no dest) — then flip the gate false, register the external refs, and enqueue the cloud deletes in one atomic commit. cancel aborts before the commit (the root stays Remote). Errors with MakeLocalError::SyncNotReady when no provider is connected.

Source

pub async fn queued_uploads(&self) -> Result<Vec<QueuedUpload>, DbError>

Every upload the durable queue is holding, oldest first.

An upload appears here the moment make_remote enqueues it — before any transfer is attempted, and whether or not sync is connected — and stays until its publication activates or its cancellation clears it. The queue is a table in the store database, so this survives restarts: a host can render “waiting to upload” without having observed the transfer that will do it.

This is a read; nothing here starts or advances a transfer. Compare drain_uploads, which does the work.

To ask whether a root still has a transition running, prefer make_remote_progress: the queue empties before the transition ends.

Source

pub fn subscribe_cloud_outbox(&self) -> CloudOutboxLiveQuery

Subscribe to the durable upload queue and make-remote intents as one committed snapshot. The first crate::CloudOutboxLiveQuery::next returns immediately; later calls wake from the same committed-change stream as row live queries.

Source

pub async fn cloud_outbox_snapshot( &self, ) -> Result<CloudOutboxSnapshot, DbError>

Read the same committed durable state the cloud-outbox subscription emits, without waiting for a change.

Source

pub async fn queued_uploads_for_root( &self, root_table: &str, root_id: &str, ) -> Result<Vec<QueuedUpload>, DbError>

The queued uploads belonging to one gated root.

The filter runs in SQL, so asking about one root does not decode every other queued upload in the store. A host answers “is anything still waiting to upload for this row?” from whether this is empty — but see make_remote_progress for whether the transition itself has finished, which outlasts its uploads.

Source

pub async fn external_blob( &self, table: &str, row_id: &str, ) -> Result<Option<ExternalBlob>, DbError>

Where the user’s own file for a row’s blob lives on disk, or None when the row has no external registration.

This is the read that mirrors SqlContext::register_external_blob: a host that needs the original file itself — to re-read its tags, to find an artifact it produced — asks here rather than reading coven’s copy, because for a user-provided blob there is no copy.

None means no registration, which is an ordinary answer: a row whose blobs coven copies, or one whose registration was cleared, has no user file to name. A registration that disagrees with the row it belongs to is an error, not a None.

Source

pub async fn queued_deletes(&self) -> Result<Vec<QueuedDelete>, DbError>

Every cloud tombstone the durable queue is holding, oldest first.

A tombstone is queued by SqlContext::enqueue_blob_delete and stays until a sync cycle carries the removal out, so this reports removals still owed to the cloud across restarts.

Source

pub async fn make_remote_progress( &self, root_table: &str, root_id: &str, ) -> Result<Option<MakeRemoteProgress>, DbError>

How far the make-remote for one gated root has got, or None when that root has none running.

This outlasts the root’s queued uploads. Once the last upload lands its queue rows are consumed, but the transition is not finished until the Store write publishing it activates — so a root can have no queued uploads and still be mid-transition, reported here as MakeRemoteProgress::Publishing.

Source

pub async fn drain_uploads(&self) -> Result<DrainOutcome, SyncError>

Drain pending blob uploads now: read each local file, seal it under its scope, write it to the cloud, and keep a retain_pinned entry’s plaintext in the protected cache.

The sync loop drains each cycle; this drives a drain directly off the connected home, against coven’s own register clock and the handle’s observer. Errors when no provider is connected (there is no cloud to write to).

The DrainOutcome says what the pass found, not just how much it moved: an empty queue, a queue held entirely in retry backoff, and a paused one are each their own answer rather than a zero count.

A host that connects with a running loop shares the queue with the cycle’s drain. The two never run at once — the queue is drained under an exclusive turn, so one entry is never in two uploads — but they do divide the work: this call may wait for a cycle’s drain and then find the entries it wanted already uploaded, and answer QueueEmpty. The outcome describes this pass, never the queue’s whole history, so a host that needs the latter should watch subscribe_cloud_outbox rather than count one drain’s return. connect_sync_with_test_home_caller_driven (test builds only) connects without a loop, so this call is the only drain and its count is the whole truth.

Source

pub async fn retry_uploads_now(&self) -> Result<DrainOutcome, SyncError>

Retry every failed upload now, without waiting for its automatic retry delay. This clears the durable delay only after confirming that a cloud connection can run the drain, then attempts the queue immediately.

Provider failures remain in the returned DrainOutcome, with their updated attempt records available through subscribe_cloud_outbox. Connection or database failures are returned as SyncError.

Source

pub async fn get_cache_budget( &self, namespace: &str, ) -> Result<Option<u64>, DbError>

Source

pub async fn set_cache_budget( &self, namespace: &str, max_bytes: u64, ) -> Result<(), DbError>

Source

pub async fn generate_restore_code(&self) -> Result<String, SyncError>

Generate a restore code, seeded with the store’s current membership-head floor read from the cloud. Requires a connected provider because minting a trustworthy floor is a network read, not a pure function of local config and keyring state — a restore code minted without one would carry no protection against a storage provider replaying an older, otherwise validly signed membership state to the device that redeems it.

Source

pub async fn get_members(&self) -> Result<Vec<MemberInfo>, SyncError>

Source

pub async fn membership_conflict( &self, ) -> Result<Option<MembershipConflictInfo>, SyncError>

Source

pub async fn start_device_pairing( &self, ) -> Result<DevicePairingHost, StartDevicePairingError>

Source

pub async fn approve_device_pairing( &self, host: &DevicePairingHost, request: &DevicePairingRequest, role: MemberRole, policy: DeviceJoinApprovalPolicy<'_>, access_administrator: Option<&dyn DeviceProviderAccessAdministrator>, on_progress: &(dyn Fn(AdmittingDeviceJoinProgress) + Send + Sync), cancel: Receiver<bool>, ) -> Result<DeviceJoinDriveOutcome, ApproveDevicePairingError>

Source

pub async fn cancel_device_pairing( &self, host: &DevicePairingHost, ) -> Result<(), ApproveDevicePairingError>

Source

pub async fn begin_device_join( &self, member_pubkey: &str, ) -> Result<DeviceJoinOffer, SyncError>

Source

pub async fn abandon_device_join( &self, offer: DeviceJoinOffer, ) -> Result<DeviceJoinAbandonment, SyncError>

Source

pub async fn authorize_device_provider_access( &self, request: DeviceProviderAccessRequest, access_administrator: Option<&dyn DeviceProviderAccessAdministrator>, ) -> Result<DeviceProviderAdmissionApproval, SyncError>

Source

pub async fn accept_device_registration_request( &self, request: DeviceRegistrationRequest, ) -> Result<ProvisionalDeviceBootstrap, SyncError>

Source

pub async fn publish_device_provider_challenge( &self, bootstrap: ProvisionalDeviceBootstrap, ) -> Result<ProviderReadyDeviceBootstrap, SyncError>

Source

pub async fn complete_device_provider_admission( &self, readiness: DeviceJoinReadiness, ) -> Result<DeviceProviderAdmissionCompletion, SyncError>

Source

pub async fn finalize_device_join( &self, completion: DeviceProviderAdmissionCompletion, ) -> Result<DeviceJoinActivation, SyncError>

Source

pub async fn device_join_status( &self, attempt_id: DeviceJoinAttemptId, role: DeviceJoinRole, ) -> Result<Option<DeviceJoinStatus>, SyncError>

Source

pub async fn resume_device_joins( &self, ) -> Result<Vec<DeviceJoinAction>, SyncError>

Source

pub async fn remove_member(&self, public_key_hex: &str) -> Result<(), SyncError>

Source

pub async fn resolve_membership_conflict( &self, choice: &MembershipConflictChoice, ) -> Result<(), SyncError>

Source

pub async fn propose_device_exclusion( &self, device_id: StoreDeviceId, ) -> Result<String, SyncError>

Propose excluding one Store device and return the code that identifies the exact activated proposal.

Source

pub async fn cancel_device_exclusion( &self, proposal_code: &str, ) -> Result<(), SyncError>

Cancel the exact Store-device exclusion proposal carried by proposal_code.

Source

pub async fn finalize_device_exclusion( &self, proposal_code: &str, ) -> Result<(), SyncError>

Finalize the exact Store-device exclusion proposal carried by proposal_code.

Source

pub async fn begin_owner_promotion( &self, device_id: StoreDeviceId, ) -> Result<String, SyncError>

Begin transferring Store ownership to an active device and return the request code that device must accept.

Source

pub async fn accept_owner_promotion( &self, request_code: &str, ) -> Result<String, SyncError>

Accept an Owner-promotion request and return the acceptance code the existing Owner must finalize.

Source

pub async fn finalize_owner_promotion( &self, acceptance_code: &str, ) -> Result<(), SyncError>

Finalize the Owner-promotion acceptance carried by acceptance_code.

Source

pub fn circles(&self) -> Circles<'_>

The Circle application surface: create, lifecycle, inspection, and typed CircleError. A borrowed namespace with no state of its own.

Source

pub async fn cleanup_intent_count_for_test( &self, namespace: &str, blob_id: &str, ) -> Result<i64, DbError>

Count cleanup obligations for one blob in integration tests.

Trait Implementations§

Source§

impl Clone for CovenHandle

Source§

fn clone(&self) -> CovenHandle

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> FromRef<T> for T
where T: Clone,

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<Unshared, Shared> IntoShared<Shared> for Unshared
where Shared: FromUnshared<Unshared>,

§

fn into_shared(self) -> Shared

Creates a shared type from an unshared type.
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,