tycode_core/modules/memory/
log.rs1use std::fs;
7use std::path::{Path, PathBuf};
8
9use anyhow::{Context, Result};
10use chrono::{DateTime, Utc};
11use serde::{Deserialize, Serialize};
12
13#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct Memory {
15 pub seq: u64,
16 pub content: String,
17 pub created_at: DateTime<Utc>,
18 pub source: Option<String>,
19}
20
21#[derive(Debug, Serialize, Deserialize)]
22struct MemoryLogInner {
23 memories: Vec<Memory>,
24 next_seq: u64,
25}
26
27#[derive(Debug)]
29pub struct MemoryLog {
30 path: PathBuf,
31}
32
33impl MemoryLog {
34 pub fn new(path: PathBuf) -> Self {
35 Self { path }
36 }
37
38 fn load_inner(&self) -> Result<MemoryLogInner> {
40 if !self.path.exists() {
41 return Ok(MemoryLogInner {
42 memories: Vec::new(),
43 next_seq: 1,
44 });
45 }
46
47 let content = fs::read_to_string(&self.path)
48 .with_context(|| format!("Failed to read memory log: {}", self.path.display()))?;
49
50 serde_json::from_str(&content)
51 .with_context(|| format!("Failed to parse memory log: {}", self.path.display()))
52 }
53
54 fn save_inner(&self, inner: &MemoryLogInner) -> Result<()> {
56 if let Some(parent) = self.path.parent() {
57 fs::create_dir_all(parent).with_context(|| {
58 format!("Failed to create memory directory: {}", parent.display())
59 })?;
60 }
61
62 let content =
63 serde_json::to_string_pretty(inner).context("Failed to serialize memory log")?;
64
65 fs::write(&self.path, content)
66 .with_context(|| format!("Failed to write memory log: {}", self.path.display()))
67 }
68
69 pub fn append(&self, content: String, source: Option<String>) -> Result<u64> {
73 let mut inner = self.load_inner()?;
74
75 let seq = inner.next_seq;
76 inner.next_seq += 1;
77
78 inner.memories.push(Memory {
79 seq,
80 content,
81 created_at: Utc::now(),
82 source,
83 });
84
85 self.save_inner(&inner)?;
86 Ok(seq)
87 }
88
89 pub fn read_all(&self) -> Result<Vec<Memory>> {
91 self.load_inner().map(|inner| inner.memories)
92 }
93
94 pub fn path(&self) -> &Path {
95 &self.path
96 }
97}