use serde::{Deserialize, Serialize};
use std::fs::{self, OpenOptions};
use std::io::{BufWriter, Write};
use std::path::PathBuf;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(tag = "t", content = "v")]
pub enum JournalEvent {
PakeStart { code_len: usize },
PakeDone,
KemSentPubkey,
KemGotCiphertext,
KeysDerived,
Rekey,
Close,
MailboxAllocated { nameplate: String },
MailboxClaimed { nameplate: String },
MailboxOpened { mailbox: String },
MailboxReleased { nameplate: String },
MailboxClosed { mailbox: String, mood: String },
SubchDuplicate { subchannel: u32, expected: u64, got: u64 },
SubchOutOfOrder { subchannel: u32, expected: u64, got: u64 },
SubchFinAfterFin { subchannel: u32 },
SubchQueueOverflow { subchannel: u32, capacity: usize },
}
pub trait Journal {
fn record(&mut self, ev: &JournalEvent);
}
pub struct FileJournal {
path: PathBuf,
}
impl FileJournal {
pub fn new(path: PathBuf) -> Self { Self { path } }
}
impl Journal for FileJournal {
fn record(&mut self, ev: &JournalEvent) {
if let Ok(f) = OpenOptions::new().create(true).append(true).open(&self.path) {
let mut w = BufWriter::new(f);
if let Ok(line) = serde_json::to_string(ev) {
let _ = writeln!(w, "{}", line);
}
let _ = w.flush();
}
}
}
pub struct NoopJournal;
impl Journal for NoopJournal {
fn record(&mut self, _ev: &JournalEvent) {}
}
pub fn read_all(path: &PathBuf) -> Vec<JournalEvent> {
let data = fs::read_to_string(path).unwrap_or_default();
data.lines()
.filter_map(|l| serde_json::from_str::<JournalEvent>(l).ok())
.collect()
}