Files
claudetools/projects/msp-tools/guru-rmm/agent/src/transport/mod.rs
Mike Swanson 07816eae46 docs: Add comprehensive project documentation from claude-projects scan
Added:
- PROJECTS_INDEX.md - Master catalog of 7 active projects
- GURURMM_API_ACCESS.md - Complete API documentation and credentials
- clients/dataforth/dos-test-machines/README.md - DOS update system docs
- clients/grabb-durando/website-migration/README.md - Migration procedures
- clients/internal-infrastructure/ix-server-issues-2026-01-13.md - Server issues
- projects/msp-tools/guru-connect/README.md - Remote desktop architecture
- projects/msp-tools/toolkit/README.md - MSP PowerShell tools
- projects/internal/acg-website-2025/README.md - Website rebuild docs
- test_gururmm_api.py - GuruRMM API testing script

Modified:
- credentials.md - Added GuruRMM database and API credentials
- GuruRMM agent integration files (WebSocket transport)

Total: 38,000+ words of comprehensive project documentation

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-22 09:58:32 -07:00

310 lines
7.4 KiB
Rust

//! Transport layer for agent-server communication
//!
//! Handles WebSocket connection to the GuruRMM server with:
//! - Auto-reconnection on disconnect
//! - Authentication via API key
//! - Sending metrics and receiving commands
//! - Heartbeat to maintain connection
mod websocket;
pub use websocket::WebSocketClient;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// Messages sent from agent to server
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "payload")]
#[serde(rename_all = "snake_case")]
pub enum AgentMessage {
/// Authentication message (sent on connect)
Auth(AuthPayload),
/// Metrics report
Metrics(crate::metrics::SystemMetrics),
/// Network state update (sent on connect and when interfaces change)
NetworkState(crate::metrics::NetworkState),
/// Command execution result
CommandResult(CommandResultPayload),
/// Watchdog event (service stopped, restarted, etc.)
WatchdogEvent(WatchdogEventPayload),
/// Update result (success, failure, rollback)
UpdateResult(UpdateResultPayload),
/// Heartbeat to keep connection alive
Heartbeat,
}
/// Authentication payload
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthPayload {
/// API key for this agent (or site)
pub api_key: String,
/// Unique device identifier (hardware-derived)
pub device_id: String,
/// Hostname of this machine
pub hostname: String,
/// Operating system type
pub os_type: String,
/// Operating system version
pub os_version: String,
/// Agent version
pub agent_version: String,
/// Architecture (amd64, arm64, etc.)
#[serde(default = "default_arch")]
pub architecture: String,
/// Previous version if reconnecting after update
#[serde(skip_serializing_if = "Option::is_none")]
pub previous_version: Option<String>,
/// Update ID if reconnecting after update
#[serde(skip_serializing_if = "Option::is_none")]
pub pending_update_id: Option<Uuid>,
}
fn default_arch() -> String {
#[cfg(target_arch = "x86_64")]
{ "amd64".to_string() }
#[cfg(target_arch = "aarch64")]
{ "arm64".to_string() }
#[cfg(not(any(target_arch = "x86_64", target_arch = "aarch64")))]
{ "unknown".to_string() }
}
/// Command execution result payload
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommandResultPayload {
/// Command ID (from the server)
pub command_id: Uuid,
/// Exit code (0 = success)
pub exit_code: i32,
/// Standard output
pub stdout: String,
/// Standard error
pub stderr: String,
/// Execution duration in milliseconds
pub duration_ms: u64,
}
/// Watchdog event payload
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WatchdogEventPayload {
/// Service or process name
pub name: String,
/// Event type
pub event: WatchdogEvent,
/// Additional details
pub details: Option<String>,
}
/// Types of watchdog events
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum WatchdogEvent {
/// Service/process was found stopped
Stopped,
/// Service/process was restarted by the agent
Restarted,
/// Restart attempt failed
RestartFailed,
/// Max restart attempts reached
MaxRestartsReached,
/// Service/process recovered on its own
Recovered,
}
/// Messages sent from server to agent
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", content = "payload")]
#[serde(rename_all = "snake_case")]
pub enum ServerMessage {
/// Authentication acknowledgment
AuthAck(AuthAckPayload),
/// Command to execute
Command(CommandPayload),
/// Configuration update
ConfigUpdate(ConfigUpdatePayload),
/// Agent update command
Update(UpdatePayload),
/// Acknowledgment of received message
Ack { message_id: Option<String> },
/// Error message
Error { code: String, message: String },
}
/// Authentication acknowledgment payload
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthAckPayload {
/// Whether authentication was successful
pub success: bool,
/// Agent ID assigned by server
pub agent_id: Option<Uuid>,
/// Error message if authentication failed
pub error: Option<String>,
}
/// Command payload from server
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommandPayload {
/// Unique command ID
pub id: Uuid,
/// Type of command
pub command_type: CommandType,
/// Command text to execute
pub command: String,
/// Optional timeout in seconds
pub timeout_seconds: Option<u64>,
/// Whether to run as elevated/admin
pub elevated: bool,
}
/// Types of commands
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CommandType {
/// Shell command (cmd on Windows, bash on Unix)
Shell,
/// PowerShell command (Windows)
PowerShell,
/// Python script
Python,
/// Raw script (requires interpreter path)
Script { interpreter: String },
/// Claude Code task execution
ClaudeTask {
/// Task description for Claude Code
task: String,
/// Optional working directory (defaults to C:\Shares\test)
working_directory: Option<String>,
/// Optional context files to provide to Claude
context_files: Option<Vec<String>>,
},
}
/// Configuration update payload
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigUpdatePayload {
/// New metrics interval (if changed)
pub metrics_interval_seconds: Option<u64>,
/// Updated watchdog config
pub watchdog: Option<WatchdogConfigUpdate>,
}
/// Watchdog configuration update
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WatchdogConfigUpdate {
/// Enable/disable watchdog
pub enabled: Option<bool>,
/// Check interval
pub check_interval_seconds: Option<u64>,
// Services and processes would be included here for remote config updates
}
/// Update command payload from server
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdatePayload {
/// Unique update ID for tracking
pub update_id: Uuid,
/// Target version to update to
pub target_version: String,
/// Download URL for the new binary
pub download_url: String,
/// SHA256 checksum of the binary
pub checksum_sha256: String,
/// Whether to force update (skip version check)
#[serde(default)]
pub force: bool,
}
/// Update result payload sent back to server
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UpdateResultPayload {
/// Update ID (from the server)
pub update_id: Uuid,
/// Update status
pub status: UpdateStatus,
/// Old version before update
pub old_version: String,
/// New version after update (if successful)
pub new_version: Option<String>,
/// Error message if failed
pub error: Option<String>,
}
/// Update status codes
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum UpdateStatus {
/// Update starting
Starting,
/// Downloading new binary
Downloading,
/// Download complete, verifying
Verifying,
/// Installing (replacing binary)
Installing,
/// Restarting service
Restarting,
/// Update completed successfully
Completed,
/// Update failed
Failed,
/// Rolled back to previous version
RolledBack,
}