1use std::fs::{self, OpenOptions};
2use std::io::Write;
3use std::path::{Path, PathBuf};
4
5use crate::error::CoreError;
6use crate::event::Event;
7
8pub struct Log {
10 path: PathBuf,
11}
12
13impl Log {
14 pub fn open(dir: impl AsRef<Path>) -> Result<Self, CoreError> {
17 let dir = dir.as_ref();
18 fs::create_dir_all(dir)?;
19 Ok(Log {
20 path: dir.join("events.ndjson"),
21 })
22 }
23
24 pub fn append(&self, ev: &Event) -> Result<(), CoreError> {
26 let line = serde_json::to_string(ev)?;
27 let mut f = OpenOptions::new()
28 .create(true)
29 .append(true)
30 .open(&self.path)?;
31 writeln!(f, "{line}")?;
32 f.sync_all()?;
33 Ok(())
34 }
35
36 pub fn read_all(&self) -> Result<Vec<Event>, CoreError> {
39 if !self.path.exists() {
40 return Ok(Vec::new());
41 }
42 let content = fs::read_to_string(&self.path)?;
43 let mut events = Vec::new();
44 for (i, line) in content.lines().enumerate() {
45 if line.trim().is_empty() {
46 continue;
47 }
48 match serde_json::from_str::<Event>(line) {
49 Ok(ev) => events.push(ev),
50 Err(e) => eprintln!("memnite: skipping corrupt log line {}: {e}", i + 1),
51 }
52 }
53 Ok(events)
54 }
55}