update
Some checks failed
Rust CI / Build Release (push) Has been cancelled
Rust CI / Cargo Check (push) Has been cancelled

This commit is contained in:
lychang
2026-07-19 15:04:22 +08:00
parent b915e69222
commit 82653c1a6c
40 changed files with 7778 additions and 1 deletions

132
src/cache/mod.rs vendored Normal file
View File

@@ -0,0 +1,132 @@
//! 缓存层 — 内存缓存管理
use crate::models::*;
use std::collections::HashMap;
use std::sync::Arc;
use tokio::sync::RwLock;
use tracing::info;
/// 相册缓存
#[derive(Debug, Clone)]
pub struct AlbumsCache {
pub albums: Vec<AlbumInfo>,
pub search_index: HashMap<String, Vec<AlbumInfo>>,
pub last_updated: chrono::DateTime<chrono::Utc>,
}
impl AlbumsCache {
pub fn new() -> Self {
Self { albums: Vec::new(), search_index: HashMap::new(), last_updated: chrono::Utc::now() }
}
pub fn is_expired(&self) -> bool {
(chrono::Utc::now() - self.last_updated).num_minutes() >= 30
}
pub fn update(&mut self, albums: Vec<AlbumInfo>) {
self.search_index.clear();
for album in &albums {
let title_lower = album.title.to_lowercase();
for word in title_lower.split_whitespace() {
if word.len() >= 2 {
self.search_index.entry(word.to_string()).or_default().push(album.clone());
}
}
self.search_index.entry(title_lower).or_default().push(album.clone());
}
self.albums = albums;
self.last_updated = chrono::Utc::now();
info!("相册缓存已更新,共 {} 个相册,{} 个搜索索引项", self.albums.len(), self.search_index.len());
}
pub fn search(&self, query: &str) -> Vec<AlbumInfo> {
let q = query.to_lowercase().trim().to_string();
if q.is_empty() { return Vec::new(); }
let mut seen = std::collections::HashSet::new();
let mut results = Vec::new();
// 1. 完整匹配
if let Some(matches) = self.search_index.get(&q) {
for album in matches {
if seen.insert(album.id) { results.push(album.clone()); }
}
}
// 2. 单词匹配
for word in q.split_whitespace() {
if word.len() >= 2 {
if let Some(matches) = self.search_index.get(word) {
for album in matches {
if seen.insert(album.id) { results.push(album.clone()); }
}
}
}
}
// 3. 模糊搜索
if results.is_empty() {
for album in &self.albums {
let tl = album.title.to_lowercase();
if tl.contains(&q) {
if seen.insert(album.id) { results.push(album.clone()); }
}
}
}
// 4. 部分匹配
if results.is_empty() && q.len() >= 2 {
for album in &self.albums {
let tl = album.title.to_lowercase();
if q.split_whitespace().any(|w| w.len() >= 2 && tl.contains(w)) {
if seen.insert(album.id) { results.push(album.clone()); }
}
}
}
results
}
}
/// 标签缓存
#[derive(Debug, Clone, Default)]
pub struct TagCache {
pub popular_tags: Vec<TagStat>,
pub last_updated: chrono::DateTime<chrono::Utc>,
}
impl TagCache {
pub fn update(&mut self, tags: Vec<TagStat>) {
self.popular_tags = tags;
self.last_updated = chrono::Utc::now();
info!("标签缓存已更新,共 {} 个热门标签", self.popular_tags.len());
}
}
/// 人物缓存
#[derive(Debug, Clone, Default)]
pub struct PersonCache {
pub persons: Vec<PersonWithCounts>,
pub last_updated: chrono::DateTime<chrono::Utc>,
}
impl PersonCache {
pub fn update(&mut self, persons: Vec<PersonWithCounts>) {
self.persons = persons;
self.last_updated = chrono::Utc::now();
info!("人物缓存已更新,共 {} 人", self.persons.len());
}
}
/// 共享缓存
pub struct AppCache {
pub albums: Arc<RwLock<AlbumsCache>>,
pub tags: Arc<RwLock<TagCache>>,
pub persons: Arc<RwLock<PersonCache>>,
}
impl AppCache {
pub fn new() -> Self {
Self {
albums: Arc::new(RwLock::new(AlbumsCache::new())),
tags: Arc::new(RwLock::new(TagCache::default())),
persons: Arc::new(RwLock::new(PersonCache::default())),
}
}
}