use crate::Error; use crate::Log; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use tokio::fs::{create_dir_all, File, OpenOptions}; use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader, BufWriter}; use tokio::sync::RwLock; use tracing::instrument; /// `EventStore` is a struct that manages the storage of event logs. pub struct EventStore { path: String, lock: Arc>, } impl EventStore { pub async fn new(path: &str) -> Result { create_dir_all(path).await?; Ok(Self { path: path.to_string(), lock: Arc::new(RwLock::new(())), }) } #[instrument(skip(self))] pub async fn save_logs(&self, logs: &[Log]) -> Result<(), Error> { let _guard = self.lock.write().await; let file_path = format!( "{}/events_{}.jsonl", self.path, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() ); let file = OpenOptions::new().create(true).append(true).open(&file_path).await?; let mut writer = BufWriter::new(file); for log in logs { let line = serde_json::to_string(log)?; writer.write_all(line.as_bytes()).await?; writer.write_all(b"\n").await?; } writer.flush().await?; tracing::info!("Saved logs to {} end", file_path); Ok(()) } pub async fn load_logs(&self) -> Result, Error> { let _guard = self.lock.read().await; let mut logs = Vec::new(); let mut entries = tokio::fs::read_dir(&self.path).await?; while let Some(entry) = entries.next_entry().await? { let file = File::open(entry.path()).await?; let reader = BufReader::new(file); let mut lines = reader.lines(); while let Some(line) = lines.next_line().await? { let log: Log = serde_json::from_str(&line)?; logs.push(log); } } Ok(logs) } }