coven_storage/
location_claim.rs1use crate::{ProviderOps, Storage, StorageConnection, StorageError, StorageFailure};
6use coven_foundation::id_source::StoreId;
7
8pub(crate) const LOCATION_MARKER: &str = "coven-location";
9pub(crate) const LOCATION_MARKER_SIZE: usize = 36;
10
11pub(crate) fn occupied() -> StorageError {
12 StorageFailure::OwnLocationRequired.into()
13}
14
15pub(crate) fn check_marker_size(size: u64) -> Result<(), StorageError> {
18 if size != LOCATION_MARKER_SIZE as u64 {
19 return Err(occupied());
20 }
21 Ok(())
22}
23
24impl<P: ProviderOps + ?Sized> StorageConnection<P> {
25 pub async fn claim_location(&self, store: StoreId) -> Result<(), StorageError> {
30 if !self.config().holds_one_store() {
31 return Ok(());
32 }
33 let created = self
36 .resent(move || async move {
37 self.cooling()?;
38 self.observed(
39 self.send(
40 crate::RequestKind::Create,
41 LOCATION_MARKER_SIZE as u64,
42 self.provider.create_location_marker(store, self.device),
43 )
44 .await,
45 )
46 .await
47 })
48 .await;
49 match created {
50 Ok(()) => Ok(()),
51 Err(error) if error.own_failure() == Some(StorageFailure::AlreadyExists) => {
52 self.check_location_claim(store).await
53 }
54 Err(error) => Err(error),
55 }
56 }
57
58 pub async fn check_location_claim(&self, store: StoreId) -> Result<(), StorageError> {
62 if !self.config().holds_one_store() {
63 return Ok(());
64 }
65 let read = self
66 .resent(move || async move {
67 self.cooling()?;
68 let read = self
69 .send(crate::RequestKind::Read, 0, self.provider.read_location_marker())
70 .await;
71 if let Ok(bytes) = &read {
72 self.received(bytes.len() as u64);
73 }
74 self.observed(read).await
75 })
76 .await;
77 match read {
78 Ok(bytes) if bytes == store.to_string().as_bytes() => Ok(()),
79 Ok(_) => Err(occupied()),
80 Err(error) if error.failure() == StorageFailure::NotFound => Err(occupied()),
81 Err(error) => Err(error),
82 }
83 }
84}
85
86#[cfg(test)]
87#[path = "location_claim_tests.rs"]
88mod tests;