1use super::*;
5
6impl MemoryStorage {
7 pub async fn rename_folder(&self, name: &str) {
10 self.provider.state.lock().await.folder_name = name.into();
11 }
12 pub async fn plant_location_marker(&self, bytes: Option<Vec<u8>>) {
14 self.provider.state.lock().await.location_marker = bytes;
15 }
16 pub fn with_publication_gate(&self, publications: Arc<dyn PublicationGate>) -> Self {
19 Self::with_gate(
20 self.provider.clone(),
21 self.device,
22 publications,
23 self.cooldown.clone(),
24 self.transfers.clone(),
25 self.provider.clock.clone(),
26 )
27 }
28
29 pub fn with_device(&self, device: coven_foundation::id_source::DeviceId) -> Self {
32 Self::with_gate(
33 self.provider.clone(),
34 device,
35 self.publications.clone(),
36 self.cooldown.clone(),
37 self.transfers.clone(),
38 self.provider.clock.clone(),
39 )
40 }
41
42 pub fn with_cooldown(&self, cooldown: Arc<dyn crate::Cooldown>) -> Self {
44 Self::with_gate(
45 self.provider.clone(),
46 self.device,
47 self.publications.clone(),
48 cooldown,
49 self.transfers.clone(),
50 self.provider.clock.clone(),
51 )
52 }
53
54 pub fn with_transfers(&self, transfers: Arc<crate::TransferBudget>) -> Self {
56 Self::with_gate(
57 self.provider.clone(),
58 self.device,
59 self.publications.clone(),
60 self.cooldown.clone(),
61 transfers,
62 self.provider.clock.clone(),
63 )
64 }
65
66 pub fn shared_connection(&self) -> Arc<StorageConnection> {
69 let connection = StorageConnection::with_gate(
70 self.provider.clone() as Arc<dyn ProviderOps>,
71 self.device,
72 self.publications.clone(),
73 self.cooldown.clone(),
74 self.transfers.clone(),
75 self.provider.clock.clone(),
76 );
77 Arc::new(connection)
78 }
79}
80
81#[async_trait]
82impl crate::providers::StorageConnector for MemoryStorage {
83 async fn account_label(
84 &self,
85 auth: crate::ProviderAuth,
86 cooldown: Arc<dyn crate::Cooldown>,
87 ) -> Result<String, StorageError> {
88 self.connect(
89 self.config(),
90 auth,
91 self.device,
92 self.publications.clone(),
93 cooldown,
94 self.transfers.clone(),
95 )
96 .await?
97 .account()
98 .await
99 }
100
101 async fn prepare_cloudkit(
102 &self,
103 container: &str,
104 _store: coven_foundation::id_source::StoreId,
105 ) -> Result<StorageConfig, StorageError> {
106 let config = self.config();
107 if !matches!(&config, StorageConfig::CloudKit { container: expected, .. } if expected == container)
108 {
109 return Err(StorageFailure::InvalidConfiguration
110 .with_source("memory connector container mismatch"));
111 }
112 Ok(config)
113 }
114 async fn connect(
115 &self,
116 config: StorageConfig,
117 auth: crate::ProviderAuth,
118 device: coven_foundation::id_source::DeviceId,
119 publications: Arc<dyn crate::PublicationGate>,
120 cooldown: Arc<dyn crate::Cooldown>,
121 transfers: Arc<crate::TransferBudget>,
122 ) -> Result<Arc<StorageConnection>, StorageError> {
123 let connection = self
124 .connect_device(config, auth)
125 .await?
126 .with_device(device)
127 .with_publication_gate(publications)
128 .with_cooldown(cooldown)
129 .with_transfers(transfers);
130 Ok(connection.shared_connection())
131 }
132 async fn detect_s3(
137 &self,
138 config: StorageConfig,
139 _credentials: crate::S3Credentials,
140 _store: coven_foundation::id_source::StoreId,
141 runs: &crate::S3DetectionRuns,
142 _waits: &crate::SetupWaits,
143 ) -> crate::S3DetectionRun {
144 let detection = async {
145 config.validate()?;
146 let StorageConfig::S3 { endpoint, profile, .. } = &config else {
147 return Err(StorageFailure::InvalidConfiguration.with_source("expected S3"));
148 };
149 Ok(conforming_detection(
150 crate::providers::s3_settings(endpoint.as_ref(), profile.as_ref())?
151 .unwrap_or(DETECTED_S3_SETTINGS),
152 ))
153 }
154 .await;
155 let cleaned = std::iter::once(runs.run).chain(runs.earlier.iter().copied()).collect();
156 crate::S3DetectionRun { detection, cleaned }
157 }
158 async fn check_new_store(
161 &self,
162 config: StorageConfig,
163 _auth: crate::ProviderAuth,
164 store: coven_foundation::id_source::StoreId,
165 _waits: &crate::SetupWaits,
166 ) -> Result<(), StorageError> {
167 config.validate()?;
168 if !config.holds_one_store() {
169 return Err(StorageFailure::InvalidConfiguration
170 .with_source("the location holds several stores, so nothing checks it"));
171 }
172 if self.provider.state.lock().await.objects.keys().any(|path| path.store() != store) {
173 return Err(StorageFailure::OwnLocationRequired.into());
174 }
175 Ok(())
176 }
177}
178
179pub const DETECTED_S3_SETTINGS: S3Settings = S3Settings {
181 signing: S3Signing::AwsSigV4,
182 single_put: S3SinglePut::IfNoneMatch,
183 copy_publication: S3CopyPublication::Never,
184 multipart_timestamp: S3MultipartTimestamp::Completion,
185 checksums: S3Checksums::Absent,
186 listing: S3Listing::V2,
187 revision: S3Revision::ETag,
188 response_headers: S3ResponseHeaders::S3,
189 request_checksums: false,
190};
191
192pub fn conforming_detection(settings: S3Settings) -> S3Detection {
194 let completion = settings.multipart_timestamp == S3MultipartTimestamp::Completion;
195 let results = [
196 (S3Probe::Signing(settings.signing), true),
197 (S3Probe::SinglePut(settings.single_put), true),
198 (S3Probe::PartialUploadHidden, true),
199 (S3Probe::ConditionalCompletion, settings.copy_publication == S3CopyPublication::Never),
200 (S3Probe::CompletionTimestamp, completion),
201 (S3Probe::CopyTimestamp, true),
202 (S3Probe::Listing(S3Listing::V1), true),
203 (S3Probe::Listing(settings.listing), true),
204 (S3Probe::ChecksumMode, settings.request_checksums),
205 (S3Probe::ChecksumReturned, settings.checksums != S3Checksums::Absent),
206 (S3Probe::ChecksumScopeStated, settings.checksums != S3Checksums::UnstatedIgnored),
207 (S3Probe::GoogleGeneration, settings.revision == S3Revision::Generation),
208 (S3Probe::GoogleHeaders, settings.response_headers == S3ResponseHeaders::Google),
209 (S3Probe::BucketList, true),
210 ]
211 .into_iter()
212 .chain(
213 settings
214 .copy_publication
215 .multipart()
216 .map(|condition| (S3Probe::CopyPublication(condition), true)),
217 )
218 .map(|(probe, held)| S3ProbeResult { probe, held, detail: "memory".into() })
219 .collect();
220 S3Detection { versioning: Ok(S3BucketVersioning::Disabled), settings, results }
221}