2023-10-01 02:36:27 +01:00
|
|
|
mod memory;
|
|
|
|
mod sqlite;
|
|
|
|
|
|
|
|
use async_trait::async_trait;
|
|
|
|
use sqlx::FromRow;
|
2023-10-02 15:33:19 +01:00
|
|
|
use std::{
|
|
|
|
fmt,
|
|
|
|
time::{SystemTime, UNIX_EPOCH},
|
|
|
|
};
|
2023-10-01 02:36:27 +01:00
|
|
|
|
|
|
|
use self::{memory::Memory, sqlite::Sqlite};
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct Cache {
|
|
|
|
memory: Memory,
|
|
|
|
sqlite: Option<Sqlite>,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn init_cache() -> Cache {
|
2023-10-02 15:33:19 +01:00
|
|
|
Cache {
|
|
|
|
memory: memory::new(),
|
|
|
|
sqlite: sqlite::new().await,
|
|
|
|
}
|
2023-10-01 02:36:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Tier enums take an i64, which is the amount of time in seconds
|
|
|
|
/// the tier should consider the contents of the cache valid.
|
|
|
|
#[derive(Clone, Debug, sqlx::Type)]
|
|
|
|
pub enum Tier {
|
|
|
|
Memory,
|
|
|
|
Sqlite,
|
|
|
|
External,
|
2023-10-02 15:33:19 +01:00
|
|
|
None,
|
2023-10-01 02:36:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Tier {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
Tier::Memory => write!(f, "memory"),
|
|
|
|
Tier::Sqlite => write!(f, "sqlite"),
|
|
|
|
Tier::External => write!(f, "external"),
|
|
|
|
Tier::None => write!(f, ""),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, FromRow)]
|
|
|
|
pub struct CachedItem {
|
|
|
|
pub content_type: String,
|
|
|
|
pub content: String,
|
|
|
|
cached: i64,
|
|
|
|
#[sqlx(default)]
|
2023-10-02 15:33:19 +01:00
|
|
|
tier: Option<Tier>,
|
2023-10-01 02:36:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl CachedItem {
|
|
|
|
pub fn tier(&self) -> Tier {
|
|
|
|
self.tier.clone().unwrap_or(Tier::None)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[async_trait]
|
2023-10-02 15:33:19 +01:00
|
|
|
pub trait CacheMechanism: Sized + Clone + Send + Sync + 'static {
|
2023-10-01 02:36:27 +01:00
|
|
|
async fn get(&self, key: &String) -> Option<CachedItem>;
|
|
|
|
async fn rm(&mut self, key: String);
|
|
|
|
async fn set(&self, key: String, item: CachedItem);
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Cache {
|
|
|
|
pub async fn get(&self, key: &String) -> Option<CachedItem> {
|
|
|
|
let m = self.memory.get(key).await;
|
|
|
|
if m.is_some() {
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
if self.sqlite.is_some() {
|
|
|
|
let sq = self.sqlite.clone().unwrap();
|
2023-10-02 15:33:19 +01:00
|
|
|
let s = sq.get(key).await;
|
|
|
|
if s.is_some() {
|
2023-10-01 02:36:27 +01:00
|
|
|
let current_time = SystemTime::now()
|
|
|
|
.duration_since(UNIX_EPOCH)
|
|
|
|
.expect("SystemTime before UNIX EPOCH!")
|
|
|
|
.as_secs()
|
|
|
|
.try_into()
|
|
|
|
.unwrap();
|
|
|
|
let mut refresh_memory = s.clone().unwrap();
|
|
|
|
refresh_memory.cached = current_time;
|
|
|
|
let _ = self.memory.set(key.clone(), refresh_memory).await;
|
2023-10-02 15:33:19 +01:00
|
|
|
return s;
|
2023-10-01 02:36:27 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-02 15:33:19 +01:00
|
|
|
return None;
|
2023-10-01 02:36:27 +01:00
|
|
|
}
|
|
|
|
|
2023-10-02 15:33:19 +01:00
|
|
|
pub async fn set(&self, key: String, content_type: String, content: String) -> bool {
|
2023-10-01 02:36:27 +01:00
|
|
|
let current_time = SystemTime::now()
|
|
|
|
.duration_since(UNIX_EPOCH)
|
|
|
|
.expect("SystemTime before UNIX EPOCH!")
|
|
|
|
.as_secs()
|
|
|
|
.try_into()
|
|
|
|
.unwrap();
|
2023-10-02 15:33:19 +01:00
|
|
|
let cached_item = CachedItem {
|
|
|
|
content_type,
|
|
|
|
content,
|
|
|
|
cached: current_time,
|
|
|
|
tier: None,
|
|
|
|
};
|
|
|
|
self.memory.set(key.clone(), cached_item.clone()).await;
|
|
|
|
if self.sqlite.is_some() {
|
|
|
|
let sq = self.sqlite.clone().unwrap();
|
|
|
|
sq.set(key.clone(), cached_item.clone()).await;
|
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
2023-10-01 02:36:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Determine whether we should actually use the cached item or not.
|
|
|
|
fn should_use(item: &CachedItem, tier: Tier) -> bool {
|
|
|
|
// TODO: Make configurable.
|
|
|
|
let cache_time = match tier {
|
2023-10-02 15:33:19 +01:00
|
|
|
Tier::Memory => 2 * 60,
|
|
|
|
Tier::Sqlite => 10 * 60,
|
2023-10-01 02:36:27 +01:00
|
|
|
Tier::External => 0,
|
|
|
|
Tier::None => 0,
|
|
|
|
};
|
2023-10-02 15:33:19 +01:00
|
|
|
|
2023-10-01 02:36:27 +01:00
|
|
|
let current_time: i64 = SystemTime::now()
|
|
|
|
.duration_since(UNIX_EPOCH)
|
|
|
|
.expect("SystemTime before UNIX EPOCH!")
|
2023-10-02 15:33:19 +01:00
|
|
|
.as_secs()
|
|
|
|
.try_into()
|
|
|
|
.unwrap();
|
2023-10-01 02:36:27 +01:00
|
|
|
|
|
|
|
current_time <= (item.cached + cache_time) && item.content != ""
|
|
|
|
}
|