use serde::{Deserialize, Serialize}; use crate::metrics::Metric; /// Message sent from agent to dashboard via ZMQ #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MetricMessage { pub hostname: String, pub timestamp: u64, pub metrics: Vec, } impl MetricMessage { pub fn new(hostname: String, metrics: Vec) -> Self { Self { hostname, timestamp: chrono::Utc::now().timestamp() as u64, metrics, } } } /// Commands that can be sent from dashboard to agent #[derive(Debug, Serialize, Deserialize)] pub enum Command { /// Request immediate metric refresh RefreshMetrics, /// Request specific metrics by name RequestMetrics { metric_names: Vec }, /// Ping command for connection testing Ping, } /// Response from agent to dashboard commands #[derive(Debug, Serialize, Deserialize)] pub enum CommandResponse { /// Acknowledgment of command Ack, /// Metrics response Metrics(Vec), /// Pong response to ping Pong, /// Error response Error { message: String }, } /// ZMQ message envelope for routing #[derive(Debug, Serialize, Deserialize)] pub struct MessageEnvelope { pub message_type: MessageType, pub payload: Vec, } #[derive(Debug, Serialize, Deserialize)] pub enum MessageType { Metrics, Command, CommandResponse, Heartbeat, } impl MessageEnvelope { pub fn metrics(message: MetricMessage) -> Result { Ok(Self { message_type: MessageType::Metrics, payload: serde_json::to_vec(&message)?, }) } pub fn command(command: Command) -> Result { Ok(Self { message_type: MessageType::Command, payload: serde_json::to_vec(&command)?, }) } pub fn command_response(response: CommandResponse) -> Result { Ok(Self { message_type: MessageType::CommandResponse, payload: serde_json::to_vec(&response)?, }) } pub fn heartbeat() -> Result { Ok(Self { message_type: MessageType::Heartbeat, payload: Vec::new(), }) } pub fn decode_metrics(&self) -> Result { match self.message_type { MessageType::Metrics => Ok(serde_json::from_slice(&self.payload)?), _ => Err(crate::SharedError::Protocol { message: "Expected metrics message".to_string(), }), } } pub fn decode_command(&self) -> Result { match self.message_type { MessageType::Command => Ok(serde_json::from_slice(&self.payload)?), _ => Err(crate::SharedError::Protocol { message: "Expected command message".to_string(), }), } } pub fn decode_command_response(&self) -> Result { match self.message_type { MessageType::CommandResponse => Ok(serde_json::from_slice(&self.payload)?), _ => Err(crate::SharedError::Protocol { message: "Expected command response message".to_string(), }), } } }