use std::collections::HashMap;
use std::time::Duration;
use async_trait::async_trait;
use crate::error::BackendError;
#[derive(Debug, Clone)]
pub struct HealthStatus {
pub is_healthy: bool,
pub latency_ms: f64,
pub backend_type: String,
pub details: HashMap<String, String>,
}
#[cfg(not(any(target_arch = "wasm32", feature = "unsync")))]
#[async_trait]
pub trait Backend: Send + Sync {
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, BackendError>;
async fn set(
&self,
key: &str,
value: Vec<u8>,
ttl: Option<Duration>,
) -> Result<(), BackendError>;
async fn delete(&self, key: &str) -> Result<bool, BackendError>;
async fn exists(&self, key: &str) -> Result<bool, BackendError>;
async fn health(&self) -> Result<HealthStatus, BackendError>;
}
#[cfg(any(target_arch = "wasm32", feature = "unsync"))]
#[async_trait(?Send)]
pub trait Backend {
async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, BackendError>;
async fn set(
&self,
key: &str,
value: Vec<u8>,
ttl: Option<Duration>,
) -> Result<(), BackendError>;
async fn delete(&self, key: &str) -> Result<bool, BackendError>;
async fn exists(&self, key: &str) -> Result<bool, BackendError>;
async fn health(&self) -> Result<HealthStatus, BackendError>;
}
#[cfg(not(any(target_arch = "wasm32", feature = "unsync")))]
#[async_trait]
pub trait TtlInspectable: Backend {
async fn ttl(&self, key: &str) -> Result<Option<Duration>, BackendError>;
async fn refresh_ttl(&self, _key: &str, _ttl: Duration) -> Result<bool, BackendError> {
Err(BackendError::permanent(
"refresh_ttl not supported by this backend",
))
}
}
#[cfg(any(target_arch = "wasm32", feature = "unsync"))]
#[async_trait(?Send)]
pub trait TtlInspectable: Backend {
async fn ttl(&self, key: &str) -> Result<Option<Duration>, BackendError>;
async fn refresh_ttl(&self, _key: &str, _ttl: Duration) -> Result<bool, BackendError> {
Err(BackendError::permanent(
"refresh_ttl not supported by this backend",
))
}
}
#[cfg(not(any(target_arch = "wasm32", feature = "unsync")))]
#[async_trait]
pub trait LockableBackend: Backend {
async fn acquire_lock(
&self,
key: &str,
timeout_ms: u64,
) -> Result<Option<String>, BackendError>;
async fn release_lock(&self, key: &str, lock_id: &str) -> Result<bool, BackendError>;
}
#[cfg(any(target_arch = "wasm32", feature = "unsync"))]
#[async_trait(?Send)]
pub trait LockableBackend: Backend {
async fn acquire_lock(
&self,
key: &str,
timeout_ms: u64,
) -> Result<Option<String>, BackendError>;
async fn release_lock(&self, key: &str, lock_id: &str) -> Result<bool, BackendError>;
}
#[cfg(all(any(feature = "file", feature = "memcached"), not(feature = "unsync")))]
pub(crate) async fn run_blocking<T: Send + 'static>(
f: impl FnOnce() -> Result<T, crate::error::BackendError> + Send + 'static,
) -> Result<T, crate::error::BackendError> {
tokio::task::spawn_blocking(f).await.map_err(|e| {
crate::error::BackendError::permanent(format!("backend blocking task failed: {e}"))
})?
}
#[cfg(all(any(feature = "file", feature = "memcached"), feature = "unsync"))]
pub(crate) async fn run_blocking<T>(
f: impl FnOnce() -> Result<T, crate::error::BackendError>,
) -> Result<T, crate::error::BackendError> {
f()
}
#[cfg(any(feature = "workers", test))]
mod saas_wire;
#[cfg(feature = "cachekitio")]
pub mod cachekitio;
#[cfg(feature = "cachekitio")]
mod cachekitio_lock;
#[cfg(feature = "cachekitio")]
mod cachekitio_ttl;
#[cfg(feature = "redis")]
pub mod redis;
#[cfg(feature = "memcached")]
pub mod memcached;
#[cfg(feature = "file")]
pub mod file;
#[cfg(feature = "workers")]
pub mod workers;