Files
User-Content-Agent/src/cache.rs
木之清泠 e8e0f421e0 feat: basic chat client with ai
connector part almostly finished.
2026-01-18 03:39:41 +08:00

146 lines
4.1 KiB
Rust

use anyhow::{Result, Context};
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::{Path, PathBuf};
/// 会话数据
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Session {
pub messages: Vec<(String, String)>, // (role, content)
pub created_at: String,
pub updated_at: String,
}
impl Session {
/// 创建新会话
pub fn new() -> Self {
let now = chrono::Local::now().to_rfc3339();
Self {
messages: Vec::new(),
created_at: now.clone(),
updated_at: now,
}
}
/// 添加消息
pub fn add_message(&mut self, role: String, content: String) {
self.messages.push((role, content));
self.updated_at = chrono::Local::now().to_rfc3339();
}
/// 获取消息列表
pub fn get_messages(&self) -> Vec<(String, String)> {
self.messages.clone()
}
}
/// 缓存管理器
pub struct CacheManager {
cache_dir: PathBuf,
}
impl CacheManager {
/// 创建缓存管理器
pub fn new() -> Result<Self> {
let cache_dir = PathBuf::from(".cache/sessions");
// 创建缓存目录
if !cache_dir.exists() {
fs::create_dir_all(&cache_dir)
.context("创建缓存目录失败")?;
}
Ok(Self { cache_dir })
}
/// 获取最新的会话文件路径
pub fn get_latest_session_path(&self) -> Option<PathBuf> {
if !self.cache_dir.exists() {
return None;
}
let mut entries: Vec<_> = fs::read_dir(&self.cache_dir)
.ok()?
.filter_map(|entry| entry.ok())
.filter(|entry| {
entry.path().extension()
.map(|ext| ext == "json")
.unwrap_or(false)
})
.collect();
// 按修改时间排序(最新的在前)
entries.sort_by_key(|entry| {
entry.metadata()
.and_then(|m| m.modified())
.unwrap_or(std::time::SystemTime::UNIX_EPOCH)
});
entries.reverse();
entries.first().map(|entry| entry.path())
}
/// 创建新的会话文件路径
pub fn create_session_path(&self) -> PathBuf {
let timestamp = chrono::Local::now().format("%Y%m%d_%H%M%S");
self.cache_dir.join(format!("session_{}.json", timestamp))
}
/// 保存会话
pub fn save_session(&self, session: &Session, path: &Path) -> Result<()> {
let json = serde_json::to_string_pretty(session)
.context("序列化会话失败")?;
fs::write(path, json)
.context("保存会话文件失败")?;
Ok(())
}
/// 加载会话
pub fn load_session(&self, path: &Path) -> Result<Session> {
let json = fs::read_to_string(path)
.context("读取会话文件失败")?;
let session: Session = serde_json::from_str(&json)
.context("解析会话文件失败")?;
Ok(session)
}
/// 获取所有会话文件
pub fn list_sessions(&self) -> Result<Vec<(String, PathBuf)>> {
if !self.cache_dir.exists() {
return Ok(Vec::new());
}
let mut sessions = Vec::new();
for entry in fs::read_dir(&self.cache_dir)? {
let entry = entry?;
let path = entry.path();
if path.extension().map(|ext| ext == "json").unwrap_or(false) {
if let Ok(metadata) = entry.metadata() {
if let Ok(modified) = metadata.modified() {
let datetime = chrono::DateTime::<chrono::Local>::from(modified);
sessions.push((datetime.format("%Y-%m-%d %H:%M:%S").to_string(), path));
}
}
}
}
// 按时间排序(最新的在前)
sessions.sort_by(|a, b| b.0.cmp(&a.0));
Ok(sessions)
}
}
// 为Session实现Default trait
impl Default for Session {
fn default() -> Self {
Self::new()
}
}