All checks were successful
Build and Release / build-and-release (push) Successful in 2m10s
Replace fragile string-based metrics with type-safe JSON data structures. Agent converts all metrics to structured data, dashboard processes typed fields. Changes: - Add AgentData struct with CPU, memory, storage, services, backup fields - Replace string parsing with direct field access throughout system - Maintain UI compatibility via temporary metric bridge conversion - Fix NVMe temperature display and eliminate string parsing bugs - Update protocol to support structured data transmission over ZMQ - Comprehensive metric type coverage: CPU, memory, storage, services, backup Version bump to 0.1.131
145 lines
4.3 KiB
Rust
145 lines
4.3 KiB
Rust
use crate::agent_data::AgentData;
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Message sent from agent to dashboard via ZMQ
|
|
/// Always structured data - no legacy metrics support
|
|
pub type AgentMessage = AgentData;
|
|
|
|
/// Command output streaming message
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct CommandOutputMessage {
|
|
pub hostname: String,
|
|
pub command_id: String,
|
|
pub command_type: String,
|
|
pub output_line: String,
|
|
pub is_complete: bool,
|
|
pub timestamp: u64,
|
|
}
|
|
|
|
|
|
impl CommandOutputMessage {
|
|
pub fn new(hostname: String, command_id: String, command_type: String, output_line: String, is_complete: bool) -> Self {
|
|
Self {
|
|
hostname,
|
|
command_id,
|
|
command_type,
|
|
output_line,
|
|
is_complete,
|
|
timestamp: chrono::Utc::now().timestamp() as u64,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 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<String> },
|
|
/// Ping command for connection testing
|
|
Ping,
|
|
}
|
|
|
|
/// Response from agent to dashboard commands
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub enum CommandResponse {
|
|
/// Acknowledgment of command
|
|
Ack,
|
|
/// Agent data response
|
|
AgentData(AgentData),
|
|
/// 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<u8>,
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub enum MessageType {
|
|
AgentData,
|
|
Command,
|
|
CommandResponse,
|
|
CommandOutput,
|
|
Heartbeat,
|
|
}
|
|
|
|
impl MessageEnvelope {
|
|
pub fn agent_data(data: AgentData) -> Result<Self, crate::SharedError> {
|
|
Ok(Self {
|
|
message_type: MessageType::AgentData,
|
|
payload: serde_json::to_vec(&data)?,
|
|
})
|
|
}
|
|
|
|
pub fn command(command: Command) -> Result<Self, crate::SharedError> {
|
|
Ok(Self {
|
|
message_type: MessageType::Command,
|
|
payload: serde_json::to_vec(&command)?,
|
|
})
|
|
}
|
|
|
|
pub fn command_response(response: CommandResponse) -> Result<Self, crate::SharedError> {
|
|
Ok(Self {
|
|
message_type: MessageType::CommandResponse,
|
|
payload: serde_json::to_vec(&response)?,
|
|
})
|
|
}
|
|
|
|
pub fn command_output(message: CommandOutputMessage) -> Result<Self, crate::SharedError> {
|
|
Ok(Self {
|
|
message_type: MessageType::CommandOutput,
|
|
payload: serde_json::to_vec(&message)?,
|
|
})
|
|
}
|
|
|
|
pub fn heartbeat() -> Result<Self, crate::SharedError> {
|
|
Ok(Self {
|
|
message_type: MessageType::Heartbeat,
|
|
payload: Vec::new(),
|
|
})
|
|
}
|
|
|
|
pub fn decode_agent_data(&self) -> Result<AgentData, crate::SharedError> {
|
|
match self.message_type {
|
|
MessageType::AgentData => Ok(serde_json::from_slice(&self.payload)?),
|
|
_ => Err(crate::SharedError::Protocol {
|
|
message: "Expected agent data message".to_string(),
|
|
}),
|
|
}
|
|
}
|
|
|
|
pub fn decode_command(&self) -> Result<Command, crate::SharedError> {
|
|
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<CommandResponse, crate::SharedError> {
|
|
match self.message_type {
|
|
MessageType::CommandResponse => Ok(serde_json::from_slice(&self.payload)?),
|
|
_ => Err(crate::SharedError::Protocol {
|
|
message: "Expected command response message".to_string(),
|
|
}),
|
|
}
|
|
}
|
|
|
|
pub fn decode_command_output(&self) -> Result<CommandOutputMessage, crate::SharedError> {
|
|
match self.message_type {
|
|
MessageType::CommandOutput => Ok(serde_json::from_slice(&self.payload)?),
|
|
_ => Err(crate::SharedError::Protocol {
|
|
message: "Expected command output message".to_string(),
|
|
}),
|
|
}
|
|
}
|
|
}
|