use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use serde::{de::DeserializeOwned, Serialize};
use crate::core::errors::{StorageError, StorageResult};
use crate::core::storage_provider::{
AsyncBlobStore, AsyncKeyValueStore, AsyncListStream, AsyncRateLimiterStore,
BlobStore, DataValue, KeyValueStore, QueryStore, RateLimiterStore, SqlRow, StorageItemStream,
};
use foundation_core::valtron::Stream;
pub struct MemoryJsonStore {
data: Arc<Mutex<HashMap<String, String>>>,
}
impl MemoryJsonStore {
#[must_use]
pub fn new() -> Self {
Self {
data: Arc::new(Mutex::new(HashMap::new())),
}
}
fn lock(&self) -> Result<std::sync::MutexGuard<'_, HashMap<String, String>>, StorageError> {
self.data
.lock()
.map_err(|e| StorageError::Backend(format!("Mutex poisoned: {e}")))
}
fn stream_many<T: Send + 'static>(vals: Vec<T>) -> StorageItemStream<'static, T> {
Box::new(vals.into_iter().map(|v| Stream::Next(Ok(v))))
}
}
impl Default for MemoryJsonStore {
fn default() -> Self {
Self::new()
}
}
impl KeyValueStore for MemoryJsonStore {
fn get<V: DeserializeOwned + Send + 'static>(&self, key: &str) -> StorageResult<Option<V>> {
let data = self.lock()?;
match data.get(key) {
Some(json) => {
let value: V =
serde_json::from_str(json).map_err(|e| StorageError::Serialization(e.to_string()))?;
Ok(Some(value))
}
None => Ok(None),
}
}
fn set<V: Serialize>(&self, key: &str, value: V) -> StorageResult<()> {
let json = serde_json::to_string(&value)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
let mut data = self.lock()?;
data.insert(key.to_string(), json);
Ok(())
}
fn delete(&self, key: &str) -> StorageResult<()> {
let mut data = self.lock()?;
data.remove(key);
Ok(())
}
fn exists(&self, key: &str) -> StorageResult<bool> {
let data = self.lock()?;
Ok(data.contains_key(key))
}
fn list_keys(&self, prefix: Option<&str>) -> StorageResult<StorageItemStream<'_, String>> {
let data = self.lock()?;
let keys: Vec<String> = data
.keys()
.filter(|k| prefix.is_none_or(|p| k.starts_with(p)))
.cloned()
.collect();
Ok(Self::stream_many(keys))
}
}
impl QueryStore for MemoryJsonStore {
fn query(
&self,
_sql: &str,
_params: &[DataValue],
) -> StorageResult<StorageItemStream<'_, SqlRow>> {
Err(StorageError::Generic(
"QueryStore not supported for MemoryJsonStore".to_string(),
))
}
fn execute(
&self,
_sql: &str,
_params: &[DataValue],
) -> StorageResult<u64> {
Err(StorageError::Generic(
"QueryStore not supported for MemoryJsonStore".to_string(),
))
}
fn execute_batch(&self, _sql: &str) -> StorageResult<()> {
Err(StorageError::Generic(
"QueryStore not supported for MemoryJsonStore".to_string(),
))
}
}
impl RateLimiterStore for MemoryJsonStore {
fn check_rate_limit(
&self,
key: &str,
max_count: u32,
window_seconds: u64,
) -> StorageResult<bool> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let rate_key = format!("_rate_limit:{key}");
let data = self.lock()?;
let allowed = match data.get(&rate_key) {
Some(json) => {
#[derive(serde::Deserialize)]
struct Entry {
count: u32,
window_start: u64,
}
let entry: Entry = serde_json::from_str(json)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
if entry.window_start < now - window_seconds {
true
} else {
entry.count < max_count
}
}
None => true,
};
Ok(allowed)
}
fn record_rate_limit(&self, key: &str) -> StorageResult<u32> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let rate_key = format!("_rate_limit:{key}");
let mut data = self.lock()?;
let new_count = if let Some(json) = data.get(&rate_key) {
#[derive(serde::Serialize, serde::Deserialize)]
struct Entry {
count: u32,
window_start: u64,
}
let mut entry: Entry = serde_json::from_str(json)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
entry.count += 1;
entry.window_start = now;
let new_json = serde_json::to_string(&entry)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
data.insert(rate_key, new_json);
entry.count
} else {
let entry = serde_json::json!({ "count": 1, "window_start": now }).to_string();
data.insert(rate_key, entry);
1
};
Ok(new_count)
}
fn reset_rate_limit(&self, key: &str) -> StorageResult<()> {
let rate_key = format!("_rate_limit:{key}");
let mut data = self.lock()?;
data.remove(&rate_key);
Ok(())
}
}
impl BlobStore for MemoryJsonStore {
fn put_blob(&self, key: &str, data: &[u8]) -> StorageResult<()> {
let encoded = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, data);
let json = serde_json::json!({ "type": "blob", "data": encoded }).to_string();
let mut store = self.lock()?;
store.insert(key.to_string(), json);
Ok(())
}
fn get_blob(&self, key: &str) -> StorageResult<Option<Vec<u8>>> {
let data = self.lock()?;
let result = data.get(key).and_then(|json| {
let wrapper: serde_json::Value = serde_json::from_str(json).ok()?;
let encoded = wrapper.get("data").and_then(|v| v.as_str())?;
base64::Engine::decode(&base64::engine::general_purpose::STANDARD, encoded).ok()
});
Ok(result)
}
fn delete_blob(&self, key: &str) -> StorageResult<()> {
let mut data = self.lock()?;
data.remove(key);
Ok(())
}
fn blob_exists(&self, key: &str) -> StorageResult<bool> {
let data = self.lock()?;
Ok(data.contains_key(key))
}
}
#[async_trait::async_trait]
impl AsyncKeyValueStore for MemoryJsonStore {
async fn get_async<V: DeserializeOwned + Send + 'static>(&self, key: &str) -> StorageResult<Option<V>> {
let data = self.lock()?;
match data.get(key) {
Some(json) => {
let value: V = serde_json::from_str(json)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
Ok(Some(value))
}
None => Ok(None),
}
}
async fn set_async<V: Serialize + Send + 'static>(&self, key: &str, value: V) -> StorageResult<()> {
let json = serde_json::to_string(&value)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
let mut data = self.lock()?;
data.insert(key.to_string(), json);
Ok(())
}
async fn delete_async(&self, key: &str) -> StorageResult<()> {
let mut data = self.lock()?;
data.remove(key);
Ok(())
}
async fn exists_async(&self, key: &str) -> StorageResult<bool> {
let data = self.lock()?;
Ok(data.contains_key(key))
}
async fn list_keys_async(&self, prefix: Option<&str>) -> StorageResult<AsyncListStream> {
let data = self.lock()?;
let keys: Vec<String> = data.keys()
.filter(|k| prefix.is_none_or(|p| k.starts_with(p)))
.cloned()
.collect();
Ok(AsyncListStream::new(futures_lite::stream::iter(
keys.into_iter().map(Ok)
)))
}
}
#[async_trait::async_trait]
impl AsyncBlobStore for MemoryJsonStore {
async fn put_blob_async(&self, key: &str, data: &[u8]) -> StorageResult<()> {
let encoded = base64::Engine::encode(&base64::engine::general_purpose::STANDARD, data);
let json = serde_json::json!({ "type": "blob", "data": encoded }).to_string();
let mut store = self.lock()?;
store.insert(key.to_string(), json);
Ok(())
}
async fn get_blob_async(&self, key: &str) -> StorageResult<Option<Vec<u8>>> {
let data = self.lock()?;
let result = data.get(key).and_then(|json| {
let wrapper: serde_json::Value = serde_json::from_str(json).ok()?;
let encoded = wrapper.get("data").and_then(|v| v.as_str())?;
base64::Engine::decode(&base64::engine::general_purpose::STANDARD, encoded).ok()
});
Ok(result)
}
async fn delete_blob_async(&self, key: &str) -> StorageResult<()> {
let mut data = self.lock()?;
data.remove(key);
Ok(())
}
async fn blob_exists_async(&self, key: &str) -> StorageResult<bool> {
let data = self.lock()?;
Ok(data.contains_key(key))
}
}
#[async_trait::async_trait]
impl AsyncRateLimiterStore for MemoryJsonStore {
async fn check_rate_limit_async(
&self,
key: &str,
max_count: u32,
window_seconds: u64,
) -> StorageResult<bool> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let rate_key = format!("_rate_limit:{key}");
let data = self.lock()?;
let allowed = match data.get(&rate_key) {
Some(json) => {
#[derive(serde::Deserialize)]
struct Entry { count: u32, window_start: u64 }
let entry: Entry = serde_json::from_str(json)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
if entry.window_start < now - window_seconds {
true
} else {
entry.count < max_count
}
}
None => true,
};
Ok(allowed)
}
async fn record_rate_limit_async(&self, key: &str) -> StorageResult<u32> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let rate_key = format!("_rate_limit:{key}");
let mut data = self.lock()?;
let new_count = if let Some(json) = data.get(&rate_key) {
#[derive(serde::Serialize, serde::Deserialize)]
struct Entry { count: u32, window_start: u64 }
let mut entry: Entry = serde_json::from_str(json)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
entry.count += 1;
entry.window_start = now;
let new_json = serde_json::to_string(&entry)
.map_err(|e| StorageError::Serialization(e.to_string()))?;
data.insert(rate_key, new_json);
entry.count
} else {
let entry = serde_json::json!({ "count": 1, "window_start": now }).to_string();
data.insert(rate_key, entry);
1
};
Ok(new_count)
}
async fn reset_rate_limit_async(&self, key: &str) -> StorageResult<()> {
let rate_key = format!("_rate_limit:{key}");
let mut data = self.lock()?;
data.remove(&rate_key);
Ok(())
}
}