use std::time::{Duration, Instant};
use moka::future::Cache as MokaCache;
use moka::Expiry;
use crate::error::Result;
use crate::router::BoxFuture;
use super::store::CacheStore;
const DEFAULT_MAX_CAPACITY: u64 = 10_000;
#[derive(Clone)]
struct Entry {
data: Vec<u8>,
ttl: Option<Duration>,
}
struct PerEntryTtl;
impl Expiry<String, Entry> for PerEntryTtl {
fn expire_after_create(
&self,
_key: &String,
value: &Entry,
_created_at: Instant,
) -> Option<Duration> {
value.ttl
}
fn expire_after_update(
&self,
_key: &String,
value: &Entry,
_updated_at: Instant,
_duration_until_expiry: Option<Duration>,
) -> Option<Duration> {
value.ttl
}
}
#[derive(Clone)]
pub struct MemoryStore {
inner: MokaCache<String, Entry>,
}
impl MemoryStore {
pub fn new() -> Self {
Self::with_capacity(DEFAULT_MAX_CAPACITY)
}
pub fn with_capacity(max_capacity: u64) -> Self {
let inner = MokaCache::builder()
.max_capacity(max_capacity)
.expire_after(PerEntryTtl)
.build();
Self { inner }
}
}
impl Default for MemoryStore {
fn default() -> Self {
Self::new()
}
}
impl CacheStore for MemoryStore {
fn get<'a>(&'a self, key: &'a str) -> BoxFuture<'a, Result<Option<Vec<u8>>>> {
Box::pin(async move { Ok(self.inner.get(key).await.map(|entry| entry.data)) })
}
fn set(&self, key: String, value: Vec<u8>, ttl: Option<Duration>) -> BoxFuture<'_, Result<()>> {
Box::pin(async move {
self.inner.insert(key, Entry { data: value, ttl }).await;
Ok(())
})
}
fn delete<'a>(&'a self, key: &'a str) -> BoxFuture<'a, Result<()>> {
Box::pin(async move {
self.inner.invalidate(key).await;
Ok(())
})
}
fn clear(&self) -> BoxFuture<'_, Result<()>> {
Box::pin(async move {
self.inner.invalidate_all();
Ok(())
})
}
}