use crate::command::command_handle::CommandHandle; use crate::command::service::CommandManagementService; use crate::telemetry::management_service::TelemetryManagementService; use actix_ws::{AggregatedMessage, ProtocolError, Session}; use anyhow::bail; use api::messages::payload::RequestMessagePayload; use api::messages::{RequestMessage, ResponseMessage}; use std::sync::Arc; use tokio::sync::mpsc::{Receiver, Sender}; use uuid::Uuid; pub(super) struct BackendConnection { session: Session, tlm_management: Arc, cmd_management: Arc, tx: Sender, commands: Vec, pub rx: Receiver, pub should_close: bool, } impl BackendConnection { pub fn new( session: Session, tlm_management: Arc, cmd_management: Arc, ) -> Self { let (tx, rx) = tokio::sync::mpsc::channel::(128); Self { session, tlm_management, cmd_management, tx, commands: vec![], rx, should_close: false, } } async fn handle_request(&mut self, msg: RequestMessage) -> anyhow::Result<()> { match msg.payload { RequestMessagePayload::TelemetryDefinitionRequest(tlm_def) => { self.tx .send(ResponseMessage { uuid: Uuid::new_v4(), response: Some(msg.uuid), payload: self.tlm_management.register(tlm_def)?.into(), }) .await?; } RequestMessagePayload::TelemetryEntry(tlm_entry) => { self.tlm_management.add_tlm_item(tlm_entry)?; } RequestMessagePayload::GenericCallbackError(_) => todo!(), RequestMessagePayload::CommandDefinition(def) => { let cmd = self .cmd_management .register_command(msg.uuid, def, self.tx.clone())?; self.commands.push(cmd); } RequestMessagePayload::CommandResponse(response) => match msg.response { None => bail!("Command Response Payload Must Respond to a Command"), Some(uuid) => { self.cmd_management .handle_command_response(uuid, response) .await?; } }, } Ok(()) } pub async fn handle_request_message( &mut self, msg: Result, ) -> anyhow::Result<()> { let msg = msg?; match msg { AggregatedMessage::Text(data) => { self.handle_request(serde_json::from_str(&data)?).await?; } AggregatedMessage::Binary(_) => { bail!("Binary Messages Unsupported"); } AggregatedMessage::Ping(bytes) => { self.session.pong(&bytes).await?; } AggregatedMessage::Pong(_) => { // Intentionally Ignore } AggregatedMessage::Close(_) => { self.should_close = true; } } Ok(()) } pub async fn handle_response(&mut self, msg: ResponseMessage) -> anyhow::Result<()> { let msg_json = serde_json::to_string(&msg)?; self.session.text(msg_json).await?; Ok(()) } pub async fn cleanup(mut self) { self.rx.close(); // Clone here to prevent conflict with the Drop trait let _ = self.session.clone().close(None).await; } } impl Drop for BackendConnection { fn drop(&mut self) { for command in self.commands.drain(..) { self.cmd_management.unregister(command); } } }