//! [TSM.ID].[11031972] -- Platform X Ecosystem //! xcu-command-center -- Supreme Command Center dashboard bridge #![deny(warnings)] use serde::{Serialize, Deserialize}; use std::collections::HashMap; use std::sync::{Arc, Mutex}; #[derive(Debug)] pub enum BridgeError { ConnectionFailed(String), ConfigError(String), OperationFailed(String), NotReady, } impl std::fmt::Display for BridgeError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::ConnectionFailed(e) => write!(f, "Connection failed: {e}"), Self::ConfigError(e) => write!(f, "Config error: {e}"), Self::OperationFailed(e) => write!(f, "Op failed: {e}"), Self::NotReady => write!(f, "Not ready"), } } } impl std::error::Error for BridgeError {} pub type Result = std::result::Result; #[derive(Debug, Clone, Serialize, Deserialize)] pub struct BridgeConfig { pub name: String, pub endpoint: String, pub params: HashMap, pub enabled: bool, } impl BridgeConfig { pub fn new(name: &str, endpoint: &str) -> Self { Self { name: name.to_string(), endpoint: endpoint.to_string(), params: HashMap::new(), enabled: true } } } #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum BridgeState { Disconnected, Connecting, Connected, Error(String) } pub struct Bridge { config: BridgeConfig, state: Arc>, message_count: Arc>, } impl Bridge { pub fn new(config: BridgeConfig) -> Result { Ok(Self { config, state: Arc::new(Mutex::new(BridgeState::Disconnected)), message_count: Arc::new(Mutex::new(0)), }) } pub fn connect(&self) -> Result<()> { let mut s = self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?; *s = BridgeState::Connecting; *s = BridgeState::Connected; Ok(()) } pub fn disconnect(&self) -> Result<()> { let mut s = self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?; *s = BridgeState::Disconnected; Ok(()) } pub fn send(&self, _payload: &[u8]) -> Result { let s = self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?; if *s != BridgeState::Connected { return Err(BridgeError::NotReady); } drop(s); let mut c = self.message_count.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?; *c += 1; Ok(*c) } pub fn state(&self) -> Result { Ok(self.state.lock().map_err(|e| BridgeError::OperationFailed(e.to_string()))?.clone()) } pub fn config(&self) -> &BridgeConfig { &self.config } } #[cfg(test)] mod tests { use super::*; #[test] fn test_bridge() { let b = Bridge::new(BridgeConfig::new("xcu-command-center", "localhost:3000")).unwrap(); assert_eq!(b.state().unwrap(), BridgeState::Disconnected); b.connect().unwrap(); assert_eq!(b.state().unwrap(), BridgeState::Connected); b.send(b"hello").unwrap(); b.disconnect().unwrap(); assert_eq!(b.state().unwrap(), BridgeState::Disconnected); } }