use fred::types::Key;
use http::Request;
use tracing::log::*;
use std::time::Duration;
pub trait CacheStrategy<B> {
fn ttl(&self) -> Duration {
Duration::from_secs(86_400)
}
fn computed_key(&self, req: &Request<B>) -> (Duration, Key);
}
#[derive(Debug, Default, Clone)]
pub struct RouteKey {}
impl<B> CacheStrategy<B> for RouteKey {
fn computed_key(&self, req: &Request<B>) -> (Duration, Key) {
let key = format!("{}-{}", req.method(), req.uri().path().to_lowercase());
trace!("computed a cache key of `{key}`");
(<RouteKey as CacheStrategy<B>>::ttl(self), key.into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_route_key() -> anyhow::Result<()> {
let strategy = RouteKey::default();
let req: Request<()> = Request::builder()
.method(http::method::Method::GET)
.uri("https://example.com/healthz")
.body(())?;
let (_, key) = strategy.computed_key(&req);
assert_eq!(key, "GET-/healthz".into());
Ok(())
}
#[test]
fn test_case_insensitive_key() -> anyhow::Result<()> {
let strategy = RouteKey::default();
let req: Request<()> = Request::builder()
.method(http::method::Method::GET)
.uri("https://example.com/HealthZ")
.body(())?;
let (_, key) = strategy.computed_key(&req);
assert_eq!(key, "GET-/healthz".into());
Ok(())
}
#[test]
fn test_key_at_root() -> anyhow::Result<()> {
let strategy = RouteKey::default();
let req: Request<()> = Request::builder()
.method(http::method::Method::GET)
.uri("https://example.com/")
.body(())?;
let (_, key) = strategy.computed_key(&req);
assert_eq!(key, "GET-/".into());
Ok(())
}
}