Skip to main content

coven/
bootstrap_status.rs

1//! What a new device tells the app as it opens, connects and loads, so the
2//! app can show that instead of a bare spinner (§13.4, E10).
3
4use super::*;
5
6/// Bootstrap progress (E10), before an open handle exists.
7#[derive(Clone, Debug, PartialEq, Eq)]
8pub enum BootstrapStatus {
9    /// Opening a store's database, with the open's steps as
10    /// `CovenBuilder::open` reports them (E1): a new installation's, which
11    /// runs every migration, or, when `restore_device` finds the restore
12    /// code's keys already installed, this device's own.
13    Opening(Progress<coven_database::OpenStep>),
14    /// Accepting provider access, connecting to storage and sending a join
15    /// request.
16    Connecting,
17    /// The join request is sent and waits for approval (§13.2).
18    WaitingForApproval {
19        /// The number the admin compares before approving.
20        confirmation: ConfirmationNumber,
21    },
22    /// Loading the store from storage: the scan for this member's keys when
23    /// the floor holds none, the floor's snapshots, then the slots after
24    /// them, each step with how much of it is done (§13.4). A waiting join's
25    /// scan for its keys is part of its wait; the check in which its keys
26    /// open, in its admission, reports that scan, and the join reports the
27    /// loading of the store it publishes after `Committing`. A restore's
28    /// registering follows the last.
29    Loading(Progress<coven_database::LoadStep>),
30    /// Registering this device once the store is loaded: a restore's check
31    /// of the access it reaches storage with, the device's registration,
32    /// whose claim first reads the slots added since loading, and the
33    /// recorded access that follows (§13.1). No count: how many slots the
34    /// claim reads isn't known until it has read them. A join never reports
35    /// it: its approval registered its device (§13.2).
36    Registering,
37    /// Keeping the member's keys and the device's credentials in custody and
38    /// publishing the store, the last work before the handle opens (§13.1);
39    /// for a join, the work between finding its admission and loading the
40    /// store it publishes (§13.2).
41    /// A replacement's swap and its reopening, reported as `Opening`, come
42    /// before it; `restore_device` also removes the installation it
43    /// replaced, a folder of any size, which has no count either.
44    Committing,
45    /// The join waits on these first unmet conditions, the records
46    /// `pending()` returns once the store is open (§19.1).
47    Pending(Vec<coven_sync::PendingRecord>),
48}
49
50/// Open a new installation's database, reporting the open's steps as
51/// `Opening` (E10). Its first open runs every migration from the start, and
52/// makes no migration write: the store it loads replaces that state.
53pub(super) async fn open_installation(
54    database: coven_database::DatabaseBuilder,
55    status: &impl Fn(BootstrapStatus),
56) -> CovenResult<Database> {
57    let database = database.loading_store();
58    let progress = database.subscribe_progress();
59    progress
60        .forward(database.open(), |progress| status(BootstrapStatus::Opening(progress)))
61        .await
62        .map_err(CovenError::from)
63}
64
65/// Run `work`, in which `sync` may load the store into the new installation,
66/// reporting loading's steps as `Loading` (E10): a restore's unlock, or the
67/// scan of the approval check in which a join's keys first open.
68pub(super) async fn loading<T>(
69    sync: &SequenceSync,
70    work: impl std::future::Future<Output = T>,
71    status: &impl Fn(BootstrapStatus),
72) -> T {
73    sync.subscribe_progress()
74        .forward(work, |progress| status(BootstrapStatus::Loading(progress)))
75        .await
76}