use std::path::PathBuf;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum NodeEvent {
NodeStarting {
node_id: u32,
},
NodeStarted {
node_id: u32,
pid: u32,
},
NodeStopping {
node_id: u32,
},
NodeStopped {
node_id: u32,
},
NodeCrashed {
node_id: u32,
exit_code: Option<i32>,
},
NodeRestarting {
node_id: u32,
attempt: u32,
},
NodeErrored {
node_id: u32,
message: String,
},
DownloadStarted {
version: String,
},
DownloadProgress {
bytes: u64,
total: u64,
},
DownloadComplete {
version: String,
path: PathBuf,
},
UpgradeScheduled {
node_id: u32,
pending_version: String,
},
NodeUpgraded {
node_id: u32,
old_version: String,
new_version: String,
},
}
impl NodeEvent {
pub fn event_type(&self) -> &'static str {
match self {
NodeEvent::NodeStarting { .. } => "node_starting",
NodeEvent::NodeStarted { .. } => "node_started",
NodeEvent::NodeStopping { .. } => "node_stopping",
NodeEvent::NodeStopped { .. } => "node_stopped",
NodeEvent::NodeCrashed { .. } => "node_crashed",
NodeEvent::NodeRestarting { .. } => "node_restarting",
NodeEvent::NodeErrored { .. } => "node_errored",
NodeEvent::DownloadStarted { .. } => "download_started",
NodeEvent::DownloadProgress { .. } => "download_progress",
NodeEvent::DownloadComplete { .. } => "download_complete",
NodeEvent::UpgradeScheduled { .. } => "upgrade_scheduled",
NodeEvent::NodeUpgraded { .. } => "node_upgraded",
}
}
}
pub trait EventListener: Send + Sync {
fn on_event(&self, event: NodeEvent);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn event_serializes_with_type_tag() {
let event = NodeEvent::NodeStarted {
node_id: 1,
pid: 1234,
};
let json = serde_json::to_string(&event).unwrap();
assert!(json.contains("\"type\":\"node_started\""));
assert!(json.contains("\"node_id\":1"));
assert!(json.contains("\"pid\":1234"));
}
#[test]
fn event_type_matches_serde_tag() {
let event = NodeEvent::NodeCrashed {
node_id: 2,
exit_code: Some(1),
};
assert_eq!(event.event_type(), "node_crashed");
let json = serde_json::to_string(&event).unwrap();
assert!(json.contains(&format!("\"type\":\"{}\"", event.event_type())));
}
#[test]
fn event_roundtrips() {
let event = NodeEvent::DownloadProgress {
bytes: 1024,
total: 4096,
};
let json = serde_json::to_string(&event).unwrap();
let deserialized: NodeEvent = serde_json::from_str(&json).unwrap();
assert_eq!(deserialized.event_type(), "download_progress");
}
#[test]
fn upgrade_scheduled_event_serializes() {
let event = NodeEvent::UpgradeScheduled {
node_id: 2,
pending_version: "0.10.11-rc.1".to_string(),
};
let json = serde_json::to_string(&event).unwrap();
assert!(json.contains("\"type\":\"upgrade_scheduled\""));
assert!(json.contains("\"node_id\":2"));
assert!(json.contains("\"pending_version\":\"0.10.11-rc.1\""));
assert_eq!(event.event_type(), "upgrade_scheduled");
}
#[test]
fn node_upgraded_event_serializes() {
let event = NodeEvent::NodeUpgraded {
node_id: 3,
old_version: "0.10.1".to_string(),
new_version: "0.10.11-rc.1".to_string(),
};
let json = serde_json::to_string(&event).unwrap();
assert!(json.contains("\"type\":\"node_upgraded\""));
assert!(json.contains("\"old_version\":\"0.10.1\""));
assert!(json.contains("\"new_version\":\"0.10.11-rc.1\""));
assert_eq!(event.event_type(), "node_upgraded");
}
}