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}