feagi_agent/core/
transport.rs1use serde::{Deserialize, Serialize};
10use std::collections::HashMap;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
14pub struct TransportConfig {
15 pub transport_type: String,
16 pub enabled: bool,
17 pub ports: HashMap<String, u16>,
18 pub host: String,
19}
20
21impl TransportConfig {
22 pub fn get_port(&self, stream: &str) -> Option<u16> {
24 self.ports.get(stream).copied()
25 }
26
27 pub fn supports_stream(&self, stream: &str) -> bool {
29 self.ports.contains_key(stream)
30 }
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
35pub struct RegistrationResponse {
36 pub status: String,
37 pub message: Option<String>,
38 pub shm_paths: Option<HashMap<String, String>>,
39 pub transports: Option<Vec<TransportConfig>>,
40 pub recommended_transport: Option<String>,
41 pub cortical_areas: serde_json::Value,
43}
44
45impl RegistrationResponse {
46 pub fn from_json(value: &serde_json::Value) -> Result<Self, feagi_structures::FeagiDataError> {
48 serde_json::from_value(value.clone()).map_err(|e| {
49 feagi_structures::FeagiDataError::DeserializationError(format!(
50 "Failed to parse registration response: {}",
51 e
52 ))
53 })
54 }
55
56 pub fn available_transports(&self) -> Vec<&TransportConfig> {
58 self.transports
59 .as_ref()
60 .map(|transports| transports.iter().filter(|t| t.enabled).collect())
61 .unwrap_or_default()
62 }
63
64 pub fn get_transport(&self, transport_type: &str) -> Option<&TransportConfig> {
66 self.transports.as_ref().and_then(|transports| {
67 transports
68 .iter()
69 .find(|t| t.transport_type == transport_type && t.enabled)
70 })
71 }
72
73 pub fn choose_transport(&self, preference: Option<&str>) -> Option<&TransportConfig> {
75 let available = self.available_transports();
76
77 if available.is_empty() {
78 return None;
79 }
80
81 if let Some(pref) = preference {
83 if let Some(transport) = self.get_transport(pref) {
84 return Some(transport);
85 }
86 }
87
88 if let Some(recommended) = &self.recommended_transport {
90 if let Some(transport) = self.get_transport(recommended) {
91 return Some(transport);
92 }
93 }
94
95 available.first().copied()
97 }
98
99 pub fn has_transport(&self, transport_type: &str) -> bool {
101 self.get_transport(transport_type).is_some()
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_parse_registration_response() {
111 let json = serde_json::json!({
112 "status": "success",
113 "message": "Agent registered successfully",
114 "transports": [
115 {
116 "transport_type": "zmq",
117 "enabled": true,
118 "ports": {
119 "sensory": 5558,
120 "motor": 5564,
121 "visualization": 5562
122 },
123 "host": "0.0.0.0"
124 },
125 {
126 "transport_type": "websocket",
127 "enabled": true,
128 "ports": {
129 "sensory": 9051,
130 "motor": 9052,
131 "visualization": 9050
132 },
133 "host": "0.0.0.0"
134 }
135 ],
136 "recommended_transport": "zmq",
137 "cortical_areas": {}
138 });
139
140 let response = RegistrationResponse::from_json(&json).unwrap();
141
142 assert_eq!(response.status, "success");
143 assert_eq!(response.available_transports().len(), 2);
144 assert!(response.has_transport("zmq"));
145 assert!(response.has_transport("websocket"));
146
147 let zmq = response.get_transport("zmq").unwrap();
148 assert_eq!(zmq.get_port("sensory"), Some(5558));
149
150 let ws = response.get_transport("websocket").unwrap();
151 assert_eq!(ws.get_port("sensory"), Some(9051));
152 }
153
154 #[test]
155 fn test_choose_transport() {
156 let json = serde_json::json!({
157 "status": "success",
158 "transports": [
159 {
160 "transport_type": "zmq",
161 "enabled": true,
162 "ports": {"sensory": 5558},
163 "host": "0.0.0.0"
164 },
165 {
166 "transport_type": "websocket",
167 "enabled": true,
168 "ports": {"sensory": 9051},
169 "host": "0.0.0.0"
170 }
171 ],
172 "recommended_transport": "zmq",
173 "cortical_areas": {}
174 });
175
176 let response = RegistrationResponse::from_json(&json).unwrap();
177
178 let auto = response.choose_transport(None).unwrap();
180 assert_eq!(auto.transport_type, "zmq");
181
182 let ws = response.choose_transport(Some("websocket")).unwrap();
184 assert_eq!(ws.transport_type, "websocket");
185
186 let zmq = response.choose_transport(Some("zmq")).unwrap();
188 assert_eq!(zmq.transport_type, "zmq");
189 }
190}