use anyhow::Result; use async_trait::async_trait; use uuid::Uuid; use super::panel_adapter::{DiscoveredServer, FileEntry, PanelAdapter, ServerStatus}; /// Companion Agent adapter. /// /// Unlike AMP and Pterodactyl which use REST APIs, the Companion Agent /// runs alongside the game server and communicates via NATS JetStream. /// Commands are published to the agent's subject namespace and responses /// are received on reply subjects. This enables direct server management /// without a panel intermediary. pub struct CompanionAdapter { pub nats: async_nats::Client, pub license_id: Uuid, } impl CompanionAdapter { pub fn new(nats: async_nats::Client, license_id: Uuid) -> Self { Self { nats, license_id } } } #[async_trait] impl PanelAdapter for CompanionAdapter { async fn test_connection(&self) -> Result { // TODO: Publish heartbeat request to corrosion.{license_id}.agent.ping, // await reply within timeout todo!() } async fn discover_servers(&self) -> Result> { // TODO: Request server info from agent via NATS request/reply. // Companion manages exactly one server, so this returns a single-element vec. todo!() } async fn get_server_status(&self, _server_id: &str) -> Result { // TODO: NATS request to corrosion.{license_id}.agent.status todo!() } async fn start_server(&self, _server_id: &str) -> Result<()> { // TODO: NATS request to corrosion.{license_id}.agent.start todo!() } async fn stop_server(&self, _server_id: &str) -> Result<()> { // TODO: NATS request to corrosion.{license_id}.agent.stop todo!() } async fn restart_server(&self, _server_id: &str) -> Result<()> { // TODO: NATS request to corrosion.{license_id}.agent.restart todo!() } async fn send_command(&self, _server_id: &str, _command: &str) -> Result { // TODO: NATS request to corrosion.{license_id}.agent.command // with command payload, await RCON response todo!() } async fn get_file(&self, _server_id: &str, _path: &str) -> Result> { // TODO: NATS request to corrosion.{license_id}.agent.file.get // Agent reads local file and returns contents todo!() } async fn put_file(&self, _server_id: &str, _path: &str, _data: &[u8]) -> Result<()> { // TODO: NATS publish to corrosion.{license_id}.agent.file.put // May need chunking for large files todo!() } async fn delete_file(&self, _server_id: &str, _path: &str) -> Result<()> { // TODO: NATS request to corrosion.{license_id}.agent.file.delete todo!() } async fn list_files(&self, _server_id: &str, _path: &str) -> Result> { // TODO: NATS request to corrosion.{license_id}.agent.file.list todo!() } async fn trigger_steam_update(&self, _server_id: &str) -> Result<()> { // TODO: NATS request to corrosion.{license_id}.agent.update // Agent runs SteamCMD locally todo!() } }