channel_log: shared disk logging with round-trip
Move IRC's disk logging to thalamus/channel_log.rs as shared functions: append_disk_log() and load_disk_log(). Any daemon can use them — opt-in, not mandatory (tmux won't use them). load_disk_log() populates a ChannelLog from disk on startup, so history survives daemon restarts. IRC daemon now uses the shared functions. Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
parent
a6ffe9e086
commit
58737a2cef
5 changed files with 72 additions and 17 deletions
|
|
@ -84,3 +84,55 @@ impl ChannelLog {
|
|||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
// ── Disk logging ───────────────────────────────────────────────
|
||||
|
||||
use std::path::PathBuf;
|
||||
|
||||
/// Append a timestamped message to a per-channel log file.
|
||||
///
|
||||
/// Log path: `{log_dir}/{channel}.log`
|
||||
/// Format: `{unix_secs} <{nick}> {text}`
|
||||
pub fn append_disk_log(log_dir: &std::path::Path, channel: &str, nick: &str, text: &str) {
|
||||
use std::io::Write;
|
||||
let filename = format!("{}.log", channel.trim_start_matches('#').to_lowercase());
|
||||
let _ = std::fs::create_dir_all(log_dir);
|
||||
if let Ok(mut f) = std::fs::OpenOptions::new()
|
||||
.create(true)
|
||||
.append(true)
|
||||
.open(log_dir.join(&filename))
|
||||
{
|
||||
let secs = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs();
|
||||
let _ = writeln!(f, "{secs} <{nick}> {text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// Load a ChannelLog from a disk log file, populating with the last N lines.
|
||||
pub fn load_disk_log(log_dir: &std::path::Path, channel: &str) -> ChannelLog {
|
||||
use std::io::{BufRead, BufReader};
|
||||
let filename = format!("{}.log", channel.trim_start_matches('#').to_lowercase());
|
||||
let path = log_dir.join(&filename);
|
||||
|
||||
let mut log = ChannelLog::new();
|
||||
let Ok(file) = std::fs::File::open(&path) else { return log };
|
||||
let reader = BufReader::new(file);
|
||||
|
||||
// Read all lines, keep only the last DEFAULT_CAPACITY
|
||||
let lines: Vec<String> = reader.lines().flatten().collect();
|
||||
for line in lines.into_iter().rev().take(DEFAULT_CAPACITY).collect::<Vec<_>>().into_iter().rev() {
|
||||
log.push(line);
|
||||
}
|
||||
// Mark all loaded lines as consumed (they're history, not new)
|
||||
log.consumed = log.total;
|
||||
log
|
||||
}
|
||||
|
||||
/// Standard log directory for a channel daemon.
|
||||
pub fn log_dir(daemon_name: &str) -> PathBuf {
|
||||
dirs::home_dir()
|
||||
.unwrap_or_default()
|
||||
.join(format!(".consciousness/channels/{}.logs", daemon_name))
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue