//! Local JSON sidecar boundary; NATS/MessagePack remains in Rust. use anyhow::{Context, Result}; use futures_util::StreamExt; use glitch_odin_lab::*; use tokio::{io::{AsyncBufReadExt, AsyncReadExt, AsyncWriteExt, BufReader}, net::TcpStream}; use std::time::Duration; async fn forward(command: Command) -> Result { let mut stream = TcpStream::connect("127.0.0.1:18768").await?; let mut bytes = serde_json::to_vec(&command)?; bytes.push(b'\n'); stream.write_all(&bytes).await?; let mut line = String::new(); BufReader::new(stream.take(65536)).read_line(&mut line).await?; let reply: Reply = serde_json::from_str(&line)?; anyhow::ensure!(!reply.state.simulated, "Expected real Godot cabinet"); Ok(reply) } pub async fn run(client: async_nats::Client) -> Result<()> { let mut subscription = client.subscribe(SUBJECT).await?; client.flush().await?; println!("Godot sidecar ready: 127.0.0.1:18768; no simulated responder"); while let Some(message) = subscription.next().await { if let Some(subject) = message.reply { let result = async { let command: Command = rmp_serde::from_slice(&message.payload)?; tokio::time::timeout(Duration::from_millis(1500), forward(command)) .await.context("Godot reply timeout")? }.await; match result { Ok(reply) => client.publish(subject, rmp_serde::to_vec_named(&reply)?.into()).await?, Err(error) => eprintln!("Godot request unconfirmed: {error:#}"), } } } Ok(()) }