1mod local;
19
20mod distributed;
21
22mod format;
23
24#[cfg(feature = "experimental_datastorage_formats")]
25pub use format::{Format, MessagePack};
26use std::marker::PhantomData;
27
28#[cfg(feature = "ll")]
29pub mod ll {
31 pub mod local {
33 pub use crate::local::*;
34 }
35
36 pub mod distributed {
38 pub use crate::distributed::*;
39 }
40}
41
42use pdk_core::classy::extract::context::ConfigureContext;
43use pdk_core::classy::extract::{Extract, FromContext};
44use pdk_core::logger;
45use serde::{de::DeserializeOwned, Serialize};
46use std::rc::Rc;
47use thiserror::Error;
48use url::form_urlencoded;
49
50use crate::distributed::DistributedStorage;
51use crate::format::{DefaultFormat, FormatWrapper};
52use crate::local::LocalStorage;
53
54#[derive(PartialEq, Eq, Debug, Clone)]
59pub enum StoreMode {
60 Always,
65 Absent,
70 Cas(String),
75}
76
77#[derive(Debug, Error)]
82#[non_exhaustive]
83pub enum DataStorageError {
84 #[error("CAS mismatch.")]
86 CasMismatch,
87 #[error("Serialization error: {0}.")]
88 #[cfg(feature = "experimental_datastorage_formats")]
89 Format(Box<dyn std::error::Error>),
91 #[error("Serialization error: {0}.")]
92 Serialization(#[from] serde_fixint::Error),
94 #[error("CAS parse error: {0}.")]
96 CasParseError(#[from] std::num::ParseIntError),
97 #[error("Timeout.")]
99 Timeout,
100 #[error("HTTP Client Error.")]
102 HttpClient,
103 #[error("Unexpected error: {0}.")]
105 Unexpected(String),
106}
107
108#[derive(Debug, Error)]
113#[non_exhaustive]
114pub enum DataStorageBuilderError {
115 #[error("Local storage not available")]
117 LocalStorageRequired,
118
119 #[error("Policy metadata not available")]
121 MetadataRequired,
122}
123
124impl From<crate::local::LocalStorageError> for DataStorageError {
125 fn from(error: crate::local::LocalStorageError) -> Self {
126 match error {
127 crate::local::LocalStorageError::CasMismatch => DataStorageError::CasMismatch,
128 _ => DataStorageError::Unexpected(error.to_string()),
129 }
130 }
131}
132
133impl From<crate::distributed::DistributedStorageError> for DataStorageError {
134 fn from(error: crate::distributed::DistributedStorageError) -> Self {
135 match error {
136 crate::distributed::DistributedStorageError::CasMismatch => {
137 DataStorageError::CasMismatch
138 }
139 crate::distributed::DistributedStorageError::Timeout => DataStorageError::Timeout,
140 crate::distributed::DistributedStorageError::HttpClient(_) => {
141 DataStorageError::HttpClient
142 }
143 error => DataStorageError::Unexpected(error.to_string()),
144 }
145 }
146}
147
148#[allow(async_fn_in_trait)]
154pub trait DataStorage {
155 async fn get_keys(&self) -> Result<Vec<String>, DataStorageError>;
157
158 async fn store<T: Serialize>(
160 &self,
161 key: &str,
162 mode: &StoreMode,
163 item: &T,
164 ) -> Result<(), DataStorageError>;
165
166 async fn get<T: DeserializeOwned>(
169 &self,
170 key: &str,
171 ) -> Result<Option<(T, String)>, DataStorageError>;
172
173 async fn delete(&self, key: &str) -> Result<(), DataStorageError>;
175
176 async fn delete_all(&self) -> Result<(), DataStorageError>;
178}
179
180pub struct LocalDataStorage<F: format::Format = format::DefaultFormat> {
185 storage: crate::local::SharedData,
186 namespace: String,
187 format: FormatWrapper<F>,
188}
189
190impl<F: format::Format> LocalDataStorage<F> {
191 pub(crate) fn new(
193 storage: crate::local::SharedData,
194 namespace: String,
195 format: FormatWrapper<F>,
196 ) -> Self {
197 Self {
198 storage,
199 namespace,
200 format,
201 }
202 }
203
204 fn convert_store_mode(
205 &self,
206 mode: &StoreMode,
207 ) -> Result<crate::local::StoreMode, DataStorageError> {
208 match mode {
209 StoreMode::Always => Ok(crate::local::StoreMode::Always),
210 StoreMode::Absent => Ok(crate::local::StoreMode::Absent),
211 StoreMode::Cas(cas_str) => {
212 let cas: u32 = cas_str.parse()?;
213 Ok(crate::local::StoreMode::Cas(cas))
214 }
215 }
216 }
217
218 fn namespaced_key(&self, key: &str) -> String {
219 format!("{}:{}", self.namespace, key)
220 }
221
222 fn get_keys(&self) -> Result<Vec<String>, DataStorageError> {
223 let all_keys = self.storage.keys();
224 let namespace_prefix = format!("{}:", self.namespace);
225 Ok(all_keys
226 .into_iter()
227 .filter(|key| key.starts_with(&namespace_prefix))
228 .map(|key| {
229 key.strip_prefix(&namespace_prefix)
230 .unwrap_or(&key)
231 .to_string()
232 })
233 .collect())
234 }
235
236 fn store<T: Serialize>(
237 &self,
238 key: &str,
239 mode: &StoreMode,
240 item: &T,
241 ) -> Result<(), DataStorageError> {
242 let serialized = self.format.serialize(item)?;
243 let local_mode = self.convert_store_mode(mode)?;
244 let namespaced_key = self.namespaced_key(key);
245 self.storage.set(&namespaced_key, &serialized, local_mode)?;
246 Ok(())
247 }
248
249 fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<(T, String)>, DataStorageError> {
250 let namespaced_key = self.namespaced_key(key);
251 match self.storage.get(&namespaced_key)? {
252 Some((data, cas)) => {
253 let deserialized: T = self.format.deserialize(&data)?;
254 Ok(Some((deserialized, cas.to_string())))
255 }
256 None => Ok(None),
257 }
258 }
259
260 fn delete(&self, key: &str) -> Result<(), DataStorageError> {
261 let namespaced_key = self.namespaced_key(key);
262 self.storage.delete(&namespaced_key)?;
263 Ok(())
264 }
265
266 fn delete_all(&self) -> Result<(), DataStorageError> {
267 let all_keys = self.storage.keys();
268 let namespace_prefix = format!("{}:", self.namespace);
269 for key in all_keys {
270 if key.starts_with(&namespace_prefix) {
271 self.storage.delete(&key)?;
272 }
273 }
274 Ok(())
275 }
276
277 #[cfg(feature = "experimental_storage_sync")]
279 pub fn blocking(&self) -> &impl BlockingDataStorage {
280 self
281 }
282}
283
284impl<F: format::Format> DataStorage for LocalDataStorage<F> {
285 async fn get_keys(&self) -> Result<Vec<String>, DataStorageError> {
286 self.get_keys()
287 }
288
289 async fn store<T: Serialize>(
290 &self,
291 key: &str,
292 mode: &StoreMode,
293 item: &T,
294 ) -> Result<(), DataStorageError> {
295 self.store(key, mode, item)
296 }
297
298 async fn get<T: DeserializeOwned>(
299 &self,
300 key: &str,
301 ) -> Result<Option<(T, String)>, DataStorageError> {
302 self.get(key)
303 }
304
305 async fn delete(&self, key: &str) -> Result<(), DataStorageError> {
306 self.delete(key)
307 }
308
309 async fn delete_all(&self) -> Result<(), DataStorageError> {
310 self.delete_all()
311 }
312}
313
314#[cfg(feature = "experimental_storage_sync")]
317pub trait BlockingDataStorage {
318 fn get_keys(&self) -> Result<Vec<String>, DataStorageError>;
320
321 fn store<T: Serialize>(
323 &self,
324 key: &str,
325 mode: &StoreMode,
326 item: &T,
327 ) -> Result<(), DataStorageError>;
328
329 fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<(T, String)>, DataStorageError>;
332
333 fn delete(&self, key: &str) -> Result<(), DataStorageError>;
335
336 fn delete_all(&self) -> Result<(), DataStorageError>;
338}
339
340#[cfg(feature = "experimental_storage_sync")]
341impl<F: format::Format> BlockingDataStorage for LocalDataStorage<F> {
342 fn get_keys(&self) -> Result<Vec<String>, DataStorageError> {
343 self.get_keys()
344 }
345
346 fn store<T: Serialize>(
347 &self,
348 key: &str,
349 mode: &StoreMode,
350 item: &T,
351 ) -> Result<(), DataStorageError> {
352 self.store(key, mode, item)
353 }
354
355 fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<(T, String)>, DataStorageError> {
356 self.get(key)
357 }
358
359 fn delete(&self, key: &str) -> Result<(), DataStorageError> {
360 self.delete(key)
361 }
362
363 fn delete_all(&self) -> Result<(), DataStorageError> {
364 self.delete_all()
365 }
366}
367
368pub struct RemoteDataStorage<F: format::Format = format::DefaultFormat> {
370 storage: Rc<crate::distributed::DistributedStorageClient>,
371 sanitized_store: String,
372 sanitized_partition: String,
373 ttl_millis: u32,
374 format: FormatWrapper<F>,
375}
376
377impl<F: format::Format> RemoteDataStorage<F> {
378 pub(crate) fn new(
381 storage: Rc<crate::distributed::DistributedStorageClient>,
382 store: String,
383 partition: String,
384 ttl_millis: u32,
385 format: FormatWrapper<F>,
386 ) -> Self {
387 let sanitized_store = form_urlencoded::byte_serialize(store.as_bytes()).collect();
389 let sanitized_partition = form_urlencoded::byte_serialize(partition.as_bytes()).collect();
390 Self {
391 storage,
392 sanitized_store,
393 sanitized_partition,
394 ttl_millis,
395 format,
396 }
397 }
398
399 fn convert_store_mode(&self, mode: &StoreMode) -> crate::distributed::StoreMode {
400 match mode {
401 StoreMode::Always => crate::distributed::StoreMode::Always,
402 StoreMode::Absent => crate::distributed::StoreMode::Absent,
403 StoreMode::Cas(cas_str) => crate::distributed::StoreMode::Cas(cas_str.clone()),
404 }
405 }
406
407 fn sanitize_key(&self, key: &str) -> String {
408 form_urlencoded::byte_serialize(key.as_bytes()).collect()
409 }
410}
411
412impl<F: format::Format> DataStorage for RemoteDataStorage<F> {
413 async fn get_keys(&self) -> Result<Vec<String>, DataStorageError> {
414 match self
416 .storage
417 .get_keys(&self.sanitized_store, &self.sanitized_partition)
418 .await
419 {
420 Ok(keys) => {
421 let decoded_keys: Vec<String> = keys
423 .into_iter()
424 .filter_map(|encoded_key| {
425 let decoded = form_urlencoded::parse(encoded_key.as_bytes())
426 .next()
427 .map(|(key, _)| key.into_owned());
428
429 if decoded.is_none() {
430 logger::debug!("Key not URL-encoded or decode failed: {encoded_key}");
431 }
432
433 decoded
434 })
435 .collect();
436
437 Ok(decoded_keys)
438 }
439 Err(e) => {
440 logger::warn!("Error getting keys: {e}");
441 Ok(vec![])
442 }
443 }
444 }
445
446 async fn store<T: Serialize>(
447 &self,
448 key: &str,
449 mode: &StoreMode,
450 item: &T,
451 ) -> Result<(), DataStorageError> {
452 let serialized = self.format.serialize(item)?;
453 let distributed_mode = self.convert_store_mode(mode);
454 let sanitized_key = self.sanitize_key(key);
455
456 match self
458 .storage
459 .store(
460 &self.sanitized_store,
461 &self.sanitized_partition,
462 &sanitized_key,
463 &distributed_mode,
464 &serialized,
465 )
466 .await
467 {
468 Ok(()) => Ok(()),
469 Err(crate::distributed::DistributedStorageError::StoreNotFound) => {
470 let store = crate::distributed::Store::new(
472 self.sanitized_store.clone(),
473 Some(self.ttl_millis),
474 None,
475 );
476
477 if let Err(e) = self.storage.upsert_store(&store).await {
479 logger::warn!("Error creating store: {e}");
480 }
481
482 self.storage
484 .store(
485 &self.sanitized_store,
486 &self.sanitized_partition,
487 &sanitized_key,
488 &distributed_mode,
489 &serialized,
490 )
491 .await?;
492 Ok(())
493 }
494 Err(e) => Err(e.into()), }
496 }
497
498 async fn get<T: DeserializeOwned>(
499 &self,
500 key: &str,
501 ) -> Result<Option<(T, String)>, DataStorageError> {
502 let sanitized_key = self.sanitize_key(key);
503 match self
504 .storage
505 .get(
506 &self.sanitized_store,
507 &self.sanitized_partition,
508 &sanitized_key,
509 )
510 .await
511 {
512 Ok((data, cas)) => {
513 let deserialized: T = self.format.deserialize(&data)?;
514 Ok(Some((deserialized, cas)))
515 }
516 Err(crate::distributed::DistributedStorageError::StoreNotFound) => {
517 logger::debug!("Store not found for key {key}, returning None");
518 Ok(None)
519 }
520 Err(crate::distributed::DistributedStorageError::KeyNotFound) => {
521 logger::debug!("Key not found: {key}");
522 Ok(None)
523 }
524 Err(e) => {
525 logger::error!("Error getting value for key {key}: {e:?}");
526 Err(e.into())
527 }
528 }
529 }
530
531 async fn delete(&self, key: &str) -> Result<(), DataStorageError> {
532 let sanitized_key = self.sanitize_key(key);
534 if let Err(e) = self
535 .storage
536 .delete(
537 &self.sanitized_store,
538 &self.sanitized_partition,
539 &sanitized_key,
540 )
541 .await
542 {
543 logger::warn!("Error deleting key {key}: {e}");
544 }
545 Ok(())
546 }
547
548 async fn delete_all(&self) -> Result<(), DataStorageError> {
549 if let Err(e) = self
551 .storage
552 .delete_partition(&self.sanitized_store, &self.sanitized_partition)
553 .await
554 {
555 logger::warn!("Error deleting partition: {e}");
556 }
557 Ok(())
558 }
559}
560
561pub struct DataStorageBuilder<F: format::Format = format::DefaultFormat> {
580 prefix: String,
581 shared_data: Rc<crate::local::SharedData>,
582 distributed_storage: Option<Rc<crate::distributed::DistributedStorageClient>>,
583 format_wrapper: FormatWrapper<F>,
584}
585
586impl<F: format::Format + Clone> Clone for DataStorageBuilder<F> {
587 fn clone(&self) -> Self {
588 Self {
589 prefix: self.prefix.clone(),
590 shared_data: Rc::clone(&self.shared_data),
591 distributed_storage: self.distributed_storage.clone(),
592 format_wrapper: self.format_wrapper.clone(),
593 }
594 }
595}
596
597impl FromContext<ConfigureContext> for DataStorageBuilder<DefaultFormat> {
608 type Error = DataStorageBuilderError;
609
610 fn from_context(context: &ConfigureContext) -> Result<Self, Self::Error> {
611 let shared_data: crate::local::SharedData = context
613 .extract()
614 .map_err(|_| DataStorageBuilderError::LocalStorageRequired)?;
615 let distributed_storage: Result<crate::distributed::DistributedStorageClient, _> =
617 context.extract();
618 let metadata: pdk_core::policy_context::api::Metadata = context
620 .extract()
621 .map_err(|_| DataStorageBuilderError::MetadataRequired)?;
622
623 let prefix = format!(
624 "isolated-storage-{}-{}",
625 metadata.policy_metadata.policy_name, metadata.policy_metadata.policy_namespace
626 );
627
628 pdk_core::logger::debug!(
629 "DataStorageBuilder: creating prefix '{}' for policy '{}' in namespace '{}'",
630 prefix,
631 metadata.policy_metadata.policy_name,
632 metadata.policy_metadata.policy_namespace
633 );
634
635 Ok(DataStorageBuilder {
636 prefix,
637 shared_data: Rc::new(shared_data),
638 distributed_storage: distributed_storage.ok().map(Rc::new),
639 format_wrapper: FormatWrapper::Default(DefaultFormat::default(), PhantomData),
640 })
641 }
642}
643
644impl<F: format::Format + Clone> DataStorageBuilder<F> {
645 pub fn shared(mut self) -> Self {
649 self.prefix = "shared-storage".to_string();
650 self
651 }
652
653 #[cfg(feature = "experimental_datastorage_formats")]
655 pub fn format<H: Format + Clone>(self, format: H) -> DataStorageBuilder<H> {
656 DataStorageBuilder {
657 prefix: self.prefix,
658 shared_data: self.shared_data,
659 distributed_storage: self.distributed_storage,
660 format_wrapper: FormatWrapper::Custom(format),
661 }
662 }
663
664 pub fn local<T: Into<String>>(&self, key: T) -> LocalDataStorage<F> {
666 let key_str = key.into();
667 let namespace = format!("{}-{}", self.prefix, key_str);
670
671 pdk_core::logger::debug!(
672 "DataStorageBuilder::local: creating namespace '{}' with prefix '{}' and key '{}'",
673 namespace,
674 self.prefix,
675 key_str
676 );
677
678 LocalDataStorage::new(
679 (*self.shared_data).clone(),
680 namespace,
681 self.format_wrapper.clone(),
682 )
683 }
684
685 pub fn remote<T: Into<String>>(&self, key: T, ttl_millis: u32) -> RemoteDataStorage<F> {
694 let key_str = key.into();
695 let storage = self
696 .distributed_storage
697 .as_ref()
698 .expect("Distributed storage not available - check if it's configured");
699 RemoteDataStorage::new(
700 Rc::clone(storage),
701 key_str.clone(),
702 key_str,
703 ttl_millis,
704 self.format_wrapper.clone(),
705 )
706 }
707}