1use crate::*;
4use coven_foundation::files::StoreDirAccess;
5
6pub use coven_foundation::files::IfUnsent;
7
8impl CovenHandle {
9 pub async fn unsent_work(&self) -> CovenResult<UnsentWork> {
14 self.database.unsent().await.map_err(CovenError::from)
15 }
16
17 pub fn subscribe_unsent_work(&self) -> LiveQuery<UnsentWork, CovenError> {
19 self.database.subscribe_unsent()
20 }
21
22 pub async fn delete_store(&self, unsent: IfUnsent) -> Result<(), StoreDeletionError> {
38 self.leave(unsent).await
39 }
40
41 pub(crate) async fn leave(&self, unsent: IfUnsent) -> Result<(), StoreDeletionError> {
45 let handle = self.clone();
46 let bugs = self.database.bugs().clone();
47 crate::task::spawn_completing("delete the store", bugs, async move {
48 handle.leaving(unsent).await
49 })
50 .await?
51 }
52
53 async fn leaving(&self, unsent: IfUnsent) -> Result<(), StoreDeletionError> {
54 if let Some(location) = self.codes.location().await? {
55 let stopped = self.database.device_stop().await.map_err(SyncError::from)?.is_some();
56 let journaled =
57 stopped || coven_sync::removal_journaled(&self.database, self.device).await?;
58 if self.codes.connection().await?.is_none() && !stopped {
59 if !journaled {
60 self.forget_deletion().await?;
61 }
62 return Err(StoreDeletionError::SignInRequired(location.provider()));
63 }
64 if !journaled {
65 let work = self.database.unsent().await.map_err(SyncError::from)?;
66 if unsent == IfUnsent::Refuse && !work.is_empty() {
67 self.forget_deletion().await?;
68 return Err(StoreDeletionError::Unsent(work));
69 }
70 #[cfg(test)]
71 let gate = self.storage.deletion_gate();
72 self.codes
73 .while_open("record the deletion", move |directory| {
74 #[cfg(test)]
75 if let Some(gate) = gate {
76 gate();
77 }
78 directory.record_deletion(unsent)
79 })
80 .await?;
81 }
82 if !stopped {
84 let retired = async {
85 self.storage.connected().await?;
86 self.storage.retire().await
87 }
88 .await;
89 if let Err(error) = retired {
90 return Err(self.retiring_failed(error).await);
91 }
92 }
93 }
94 self.close().await.map_err(StoreDeletionError::Closing)?;
95 let directory = self.directory.clone();
96 let keychain = self.keychain.clone();
97 let bugs = self.database.bugs().clone();
98 crate::task::blocking_completing("delete the store", bugs, move || {
99 crate::coven::delete::<StoreDeletionError>(&directory, &keychain)
100 })
101 .await?
102 }
103
104 async fn retiring_failed(&self, error: SyncError) -> StoreDeletionError {
109 let journaled = async {
110 Ok::<_, SyncError>(
111 self.database.device_stop().await?.is_some()
112 || coven_sync::removal_journaled(&self.database, self.device).await?,
113 )
114 }
115 .await;
116 match journaled {
117 Ok(false) => match self.forget_deletion().await {
118 Ok(()) => StoreDeletionError::from(error),
119 Err(cleanup) => StoreDeletionError::from(SyncError::cleanup(error, cleanup)),
120 },
121 Ok(true) => StoreDeletionError::Unfinished(match self.close().await {
122 Ok(()) => error,
123 Err(cleanup) => SyncError::cleanup(error, cleanup),
124 }),
125 Err(read) => StoreDeletionError::Unfinished(SyncError::cleanup(error, read)),
128 }
129 }
130
131 async fn forget_deletion(&self) -> Result<(), SyncError> {
134 let directory = self.directory.clone();
135 let bugs = self.database.bugs().clone();
136 crate::task::blocking_completing("forget the deletion", bugs, move || {
137 directory.forget_deletion()
138 })
139 .await
140 .map_err(SyncError::from)?
141 .map_err(SyncError::from)
142 }
143}
144
145#[cfg(test)]
146#[path = "handle_delete_tests.rs"]
147mod tests;