1use std::cell::RefCell;
2use std::marker::PhantomData;
3use std::rc::Rc;
4
5use infinity_bridge_wire::{BridgeError, EventPayload, WireMsg};
6use serde_json::Value;
7
8use crate::backend::CommBusBackend;
9
10pub struct BridgeConfig {
11 pub call_event: String,
12 pub response_event: String,
13}
14
15impl BridgeConfig {
16 pub fn new(call_event: impl Into<String>, response_event: impl Into<String>) -> Self {
17 Self {
18 call_event: call_event.into(),
19 response_event: response_event.into(),
20 }
21 }
22}
23
24pub trait BridgeHandler: 'static {
25 fn on_command(&self, name: Option<&str>, payload: &Value) -> Result<Value, String>;
30
31 fn on_event(&self, _name: &str, _data: &Value) {}
35}
36
37impl<F> BridgeHandler for F
38where
39 F: Fn(Option<&str>, &Value) -> Result<Value, String> + 'static,
40{
41 fn on_command(&self, name: Option<&str>, payload: &Value) -> Result<Value, String> {
42 (self)(name, payload)
43 }
44}
45
46type CommandFn = Box<dyn Fn(&Value) -> Result<Value, String>>;
47type EventFn = Box<dyn Fn(&Value)>;
48
49pub struct Router {
89 commands: Vec<(&'static str, CommandFn)>,
90 events: Vec<(&'static str, EventFn)>,
91 fallback: Option<Box<dyn Fn(Option<&str>, &Value) -> Result<Value, String>>>,
92}
93
94impl Router {
95 pub fn new() -> Self {
96 Self {
97 commands: Vec::new(),
98 events: Vec::new(),
99 fallback: None,
100 }
101 }
102
103 pub fn command(
104 mut self,
105 name: &'static str,
106 handler: impl Fn(&Value) -> Result<Value, String> + 'static,
107 ) -> Self {
108 self.commands.push((name, Box::new(handler)));
109 self
110 }
111
112 pub fn event(mut self, name: &'static str, handler: impl Fn(&Value) + 'static) -> Self {
113 self.events.push((name, Box::new(handler)));
114 self
115 }
116
117 pub fn fallback(
118 mut self,
119 handler: impl Fn(Option<&str>, &Value) -> Result<Value, String> + 'static,
120 ) -> Self {
121 self.fallback = Some(Box::new(handler));
122 self
123 }
124}
125
126impl BridgeHandler for Router {
127 fn on_command(&self, name: Option<&str>, payload: &Value) -> Result<Value, String> {
128 if let Some(name) = name {
129 for (cmd_name, handler) in &self.commands {
130 if *cmd_name == name {
131 return handler(payload);
132 }
133 }
134 }
135 if let Some(ref fallback) = self.fallback {
136 return fallback(name, payload);
137 }
138
139 Err(format!("UNKNOWN_COMMAND: {}", name.unwrap_or("<unnamed>")))
140 }
141
142 fn on_event(&self, name: &str, data: &Value) {
143 for (evt_name, handler) in &self.events {
144 if *evt_name == name {
145 handler(data);
146 return;
147 }
148 }
149 }
150}
151
152#[derive(serde::Deserialize)]
153struct CommBusEnvelope {
154 #[serde(rename = "requestId")]
155 request_id: String,
156 payload: Value,
157}
158
159#[derive(serde::Serialize)]
160struct CommBusResponse {
161 #[serde(rename = "requestId")]
162 request_id: String,
163 ok: bool,
164 #[serde(skip_serializing_if = "Option::is_none")]
165 response: Option<Value>,
166 #[serde(skip_serializing_if = "Option::is_none")]
167 error: Option<String>,
168}
169
170struct BridgeShared {
171 response_event: String,
172}
173
174pub struct Bridge<B: CommBusBackend> {
175 _subscription: B::Subscription,
176 shared: Rc<RefCell<BridgeShared>>,
177 _marker: PhantomData<B>,
178}
179
180impl<B: CommBusBackend> Bridge<B> {
181 pub fn new(config: BridgeConfig, handler: impl BridgeHandler) -> Result<Self, BridgeError> {
182 let shared = Rc::new(RefCell::new(BridgeShared {
183 response_event: config.response_event.clone(),
184 }));
185
186 let shared_for_cb = Rc::clone(&shared);
187
188 let subscription = B::subscribe(&config.call_event, move |raw| {
189 Self::dispatch(&shared_for_cb, &handler, raw);
190 })
191 .map_err(|e| BridgeError::transport(format!("CommBus subscribe failed: {e}")))?;
192
193 Ok(Self {
194 _subscription: subscription,
195 shared,
196 _marker: PhantomData,
197 })
198 }
199
200 fn dispatch(shared: &Rc<RefCell<BridgeShared>>, handler: &impl BridgeHandler, raw: &str) {
201 let envelope: CommBusEnvelope = match serde_json::from_str(raw) {
202 Ok(e) => e,
203 Err(e) => {
204 eprintln!("[msfs-bridge] Failed to parse CommBus envelope: {e}");
205 return;
206 }
207 };
208
209 let payload_str = match serde_json::to_string(&envelope.payload) {
210 Ok(s) => s,
211 Err(_) => {
212 Self::send_response(
213 shared,
214 &envelope.request_id,
215 Err("internal: re-serialize failed".into()),
216 );
217 return;
218 }
219 };
220
221 match WireMsg::from_json(&payload_str) {
222 Ok(WireMsg::Cmd(cmd)) => {
223 let result = handler.on_command(cmd.name.as_deref(), &cmd.payload);
224 Self::send_response(shared, &envelope.request_id, result);
225 }
226 Ok(WireMsg::Event(evt)) => {
227 handler.on_event(&evt.name, &evt.data);
228 }
229 _ => {
230 let result = handler.on_command(None, &envelope.payload);
231 Self::send_response(shared, &envelope.request_id, result);
232 }
233 }
234 }
235
236 fn send_response(
237 shared: &Rc<RefCell<BridgeShared>>,
238 request_id: &str,
239 result: Result<Value, String>,
240 ) {
241 let response = CommBusResponse {
242 request_id: request_id.to_string(),
243 ok: result.is_ok(),
244 response: result.as_ref().ok().cloned(),
245 error: result.err(),
246 };
247
248 let resp_json = match serde_json::to_string(&response) {
249 Ok(j) => j,
250 Err(e) => {
251 eprintln!("[msfs-bridge] Failed to serialize response: {e}");
252 return;
253 }
254 };
255
256 let event_name = shared.borrow().response_event.clone();
257
258 if let Err(e) = B::call(&event_name, &resp_json) {
259 eprintln!("[msfs-bridge] CommBus send failed: {e}");
260 }
261 }
262
263 pub fn emit(&self, name: impl Into<String>, data: Value) -> Result<(), BridgeError> {
264 let msg = WireMsg::Event(EventPayload::new(name, data));
265 let json = msg.to_json()?;
266
267 let event_name = self.shared.borrow().response_event.clone();
268
269 B::call(&event_name, &json)
270 .map_err(|e| BridgeError::transport(format!("CommBus send failed: {e}")))
271 }
272}