1use crate::common::ApiState;
12use crate::common::{ApiError, ApiResult, Json, State};
13use crate::v1::{
14 ConnectionInfoApi, ConnectionInfoBluetooth, ConnectionInfoShm, ConnectionInfoStreamStatus,
15 ConnectionInfoUdp, ConnectionInfoWebSocket, ConnectionInfoWebSocketEndpoints,
16 ConnectionInfoWebSocketPorts, ConnectionInfoZmq, ConnectionInfoZmqEndpoints,
17 ConnectionInfoZmqPorts, NetworkConnectionInfo,
18};
19use serde_json::{json, Value};
20use std::collections::HashMap;
21
22#[utoipa::path(
28 get,
29 path = "/v1/network/status",
30 tag = "network",
31 responses(
32 (status = 200, description = "Network status", body = HashMap<String, serde_json::Value>),
33 (status = 500, description = "Internal server error")
34 )
35)]
36pub async fn get_status(State(_state): State<ApiState>) -> ApiResult<Json<HashMap<String, Value>>> {
37 let mut response = HashMap::new();
39 response.insert("zmq_enabled".to_string(), json!(false));
40 response.insert("http_enabled".to_string(), json!(true));
41 response.insert("websocket_enabled".to_string(), json!(false));
42
43 Ok(Json(response))
44}
45
46#[utoipa::path(
48 post,
49 path = "/v1/network/config",
50 tag = "network",
51 responses(
52 (status = 200, description = "Network configured", body = HashMap<String, String>),
53 (status = 500, description = "Internal server error")
54 )
55)]
56pub async fn post_config(
57 State(_state): State<ApiState>,
58 Json(request): Json<HashMap<String, Value>>,
59) -> ApiResult<Json<HashMap<String, String>>> {
60 let _config = request
62 .get("config")
63 .ok_or_else(|| ApiError::invalid_input("Missing 'config' field"))?;
64
65 tracing::info!(target: "feagi-api", "Network configuration updated");
67
68 Ok(Json(HashMap::from([(
69 "message".to_string(),
70 "Network configured successfully".to_string(),
71 )])))
72}
73
74pub trait NetworkConnectionInfoProvider: Send + Sync {
80 fn get(&self) -> NetworkConnectionInfo;
81}
82
83#[utoipa::path(
85 get,
86 path = "/v1/network/connection_info",
87 tag = "network",
88 responses(
89 (status = 200, description = "Network connection info", body = NetworkConnectionInfo),
90 (status = 500, description = "Internal server error")
91 )
92)]
93pub async fn get_connection_info(
94 State(state): State<ApiState>,
95) -> ApiResult<Json<NetworkConnectionInfo>> {
96 let info = state
97 .network_connection_info_provider
98 .as_ref()
99 .map(|p| p.get())
100 .unwrap_or_else(placeholder_connection_info);
101
102 Ok(Json(info))
103}
104
105fn placeholder_connection_info() -> NetworkConnectionInfo {
106 NetworkConnectionInfo {
107 api: ConnectionInfoApi {
108 enabled: true,
109 base_url: "http://127.0.0.1:8000".to_string(),
110 host: "127.0.0.1".to_string(),
111 port: 8000,
112 swagger_url: "http://127.0.0.1:8000/swagger-ui/".to_string(),
113 },
114 zmq: ConnectionInfoZmq {
115 enabled: false,
116 host: "127.0.0.1".to_string(),
117 ports: ConnectionInfoZmqPorts {
118 registration: 30001,
119 sensory: 5558,
120 motor: 5564,
121 visualization: 5562,
122 api_control: 5565,
123 },
124 endpoints: ConnectionInfoZmqEndpoints {
125 registration: "tcp://127.0.0.1:30001".to_string(),
126 sensory: "tcp://127.0.0.1:5558".to_string(),
127 motor: "tcp://127.0.0.1:5564".to_string(),
128 visualization: "tcp://127.0.0.1:5562".to_string(),
129 },
130 },
131 websocket: ConnectionInfoWebSocket {
132 enabled: false,
133 host: "127.0.0.1".to_string(),
134 ports: ConnectionInfoWebSocketPorts {
135 registration: 9053,
136 sensory: 9051,
137 motor: 9052,
138 visualization: 9050,
139 rest_api: 9054,
140 },
141 endpoints: ConnectionInfoWebSocketEndpoints {
142 registration: "ws://127.0.0.1:9053".to_string(),
143 sensory: "ws://127.0.0.1:9051".to_string(),
144 motor: "ws://127.0.0.1:9052".to_string(),
145 visualization: "ws://127.0.0.1:9050".to_string(),
146 },
147 },
148 shm: ConnectionInfoShm {
149 enabled: false,
150 base_path: "/tmp".to_string(),
151 policy: "auto".to_string(),
152 note: "Actual paths are allocated per-agent at registration".to_string(),
153 },
154 udp: ConnectionInfoUdp {
155 enabled: false,
156 visualization: None,
157 sensory: None,
158 note: "Placeholder for future UDP transport support".to_string(),
159 },
160 bluetooth: ConnectionInfoBluetooth {
161 enabled: false,
162 relay_port: None,
163 note: "Placeholder for future use. Bluetooth relay is provided by feagi-desktop for embodied controllers, not by FEAGI server".to_string(),
164 },
165 stream_status: ConnectionInfoStreamStatus {
166 zmq_control_started: false,
167 zmq_data_streams_started: false,
168 websocket_started: false,
169 note: "Data streams start when genome is loaded and agents with matching capabilities are registered"
170 .to_string(),
171 },
172 }
173}