update
This commit is contained in:
132
src/cache/mod.rs
vendored
Normal file
132
src/cache/mod.rs
vendored
Normal 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())),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user