No central server, user-owned data, reverse-chronological feed. Rust core + Tauri desktop + Android app + plain HTML/CSS/JS frontend. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
73 lines
1.6 KiB
Rust
73 lines
1.6 KiB
Rust
use std::collections::VecDeque;
|
|
|
|
use serde::Serialize;
|
|
|
|
const MAX_EVENTS: usize = 200;
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum ActivityLevel {
|
|
Info,
|
|
Warn,
|
|
Error,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, Serialize, PartialEq, Eq)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum ActivityCategory {
|
|
Growth,
|
|
Rebalance,
|
|
Recovery,
|
|
Anchor,
|
|
Connection,
|
|
Relay,
|
|
}
|
|
|
|
#[derive(Debug, Clone, Serialize)]
|
|
pub struct ActivityEvent {
|
|
pub timestamp_ms: u64,
|
|
pub level: ActivityLevel,
|
|
pub category: ActivityCategory,
|
|
pub message: String,
|
|
pub peer_id: Option<[u8; 32]>,
|
|
}
|
|
|
|
pub struct ActivityLog {
|
|
events: VecDeque<ActivityEvent>,
|
|
}
|
|
|
|
impl ActivityLog {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
events: VecDeque::with_capacity(MAX_EVENTS),
|
|
}
|
|
}
|
|
|
|
pub fn log(
|
|
&mut self,
|
|
level: ActivityLevel,
|
|
cat: ActivityCategory,
|
|
msg: String,
|
|
peer: Option<[u8; 32]>,
|
|
) {
|
|
let now = std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap_or_default()
|
|
.as_millis() as u64;
|
|
if self.events.len() >= MAX_EVENTS {
|
|
self.events.pop_front();
|
|
}
|
|
self.events.push_back(ActivityEvent {
|
|
timestamp_ms: now,
|
|
level,
|
|
category: cat,
|
|
message: msg,
|
|
peer_id: peer,
|
|
});
|
|
}
|
|
|
|
pub fn recent(&self, limit: usize) -> Vec<ActivityEvent> {
|
|
let start = self.events.len().saturating_sub(limit);
|
|
self.events.iter().skip(start).cloned().collect()
|
|
}
|
|
}
|