use axum::http::HeaderMap;
use brk_types::{BlockHashPrefix, Version};
use crate::{VERSION, etag::Etag, extended::HeaderMapExtended};
use super::{
mode::{CDN_LIVE, cdn_cached},
strategy::CacheStrategy,
};
const CC: &str = "public, no-cache, stale-if-error=86400";
const CC_ERROR: &str = "public, max-age=1, must-revalidate";
pub struct CacheParams {
pub etag: Etag,
cache_control: &'static str,
cdn_cache_control: &'static str,
}
impl CacheParams {
fn tip(tip: BlockHashPrefix) -> Self {
Self {
etag: format!("t{:x}", *tip).into(),
cache_control: CC,
cdn_cache_control: CDN_LIVE,
}
}
fn immutable(version: Version) -> Self {
Self {
etag: format!("i{version}").into(),
cache_control: CC,
cdn_cache_control: cdn_cached(),
}
}
fn block_bound(version: Version, prefix: BlockHashPrefix) -> Self {
Self {
etag: format!("b{version}-{:x}", *prefix).into(),
cache_control: CC,
cdn_cache_control: cdn_cached(),
}
}
pub fn deploy() -> Self {
Self {
etag: format!("d{VERSION}").into(),
cache_control: CC,
cdn_cache_control: cdn_cached(),
}
}
fn mempool_hash(hash: u64) -> Self {
Self {
etag: format!("m{hash:x}").into(),
cache_control: CC,
cdn_cache_control: CDN_LIVE,
}
}
pub fn series(version: Version, total: usize, end: usize, hash: BlockHashPrefix) -> Self {
let v = u32::from(version);
if end >= total {
Self {
etag: format!("s{v}-{:x}", *hash).into(),
cache_control: CC,
cdn_cache_control: CDN_LIVE,
}
} else {
Self {
etag: format!("s{v}-{total}").into(),
cache_control: CC,
cdn_cache_control: cdn_cached(),
}
}
}
pub fn error(etag: Etag) -> Self {
Self {
etag,
cache_control: CC_ERROR,
cdn_cache_control: CC_ERROR,
}
}
pub fn apply_error_cache_control(headers: &mut HeaderMap) {
headers.insert_cache_control(CC_ERROR);
headers.insert_cdn_cache_control(CC_ERROR);
}
pub fn matches_etag(&self, headers: &HeaderMap) -> bool {
headers.has_etag(self.etag.as_str())
}
pub fn apply_to(&self, headers: &mut HeaderMap) {
headers.insert_etag(self.etag.as_str());
headers.insert_cache_control(self.cache_control);
headers.insert_cdn_cache_control(self.cdn_cache_control);
}
pub fn resolve(strategy: &CacheStrategy, tip: BlockHashPrefix) -> Self {
match strategy {
CacheStrategy::Tip => Self::tip(tip),
CacheStrategy::Immutable(v) => Self::immutable(*v),
CacheStrategy::BlockBound(v, prefix) => Self::block_bound(*v, *prefix),
CacheStrategy::Deploy => Self::deploy(),
CacheStrategy::MempoolHash(hash) => Self::mempool_hash(*hash),
}
}
}