feat(simulation): demux inbound bridge stream — receive() + atlas routing (#969, D-225)
Replaces the fixed-type SimBridge::receive_inputs() with a tagged receive() -> Option<Inbound>, where Inbound is Inputs(Vec<PlayerInput>) or AtlasRequest(AtlasLayerRequest). A shared decode_inbound() demuxes a frame by shape (msgpack array = inputs, map = atlas request) — additive, no wire change to existing input/snapshot frames. Adds send_atlas_response() to the trait (both TcpBridge + LocalBridge impls). receive_bridge_inputs routes inputs to the InputQueue as before; atlas requests to a new AtlasRequestBuffer (drained by the serve system next). Integration tests (bridge_tcp/bridge_ipc) updated to the tagged receive(); a demux unit test covers all three branches. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
+14
-23
@@ -2,7 +2,8 @@
|
||||
// Implements D-020 subprocess/IPC architecture
|
||||
// Deterministic client-server communication via Unix domain sockets
|
||||
|
||||
use super::{BridgeError, ObserverSnapshot, PlayerInput, SimBridge};
|
||||
use super::{decode_inbound, BridgeError, Inbound, ObserverSnapshot, SimBridge};
|
||||
use crate::atlas::layer_proxy::AtlasLayerResponse;
|
||||
use crate::bridge::framing::{read_framed, write_framed};
|
||||
use std::fs;
|
||||
use std::io::{BufReader, BufWriter};
|
||||
@@ -123,37 +124,27 @@ impl SimBridge for LocalBridge {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn receive_inputs(&self) -> Result<Vec<PlayerInput>, BridgeError> {
|
||||
fn receive(&self) -> Result<Option<Inbound>, BridgeError> {
|
||||
let mut reader = self
|
||||
.reader
|
||||
.lock()
|
||||
.map_err(|e| BridgeError::MutexPoisoned(format!("reader: {}", e)))?;
|
||||
|
||||
match read_framed(reader.get_mut())? {
|
||||
Some(payload) => match rmp_serde::from_slice::<Vec<PlayerInput>>(&payload) {
|
||||
Ok(inputs) => {
|
||||
tracing::trace!("received {} inputs", inputs.len());
|
||||
Ok(inputs)
|
||||
}
|
||||
Err(e) => {
|
||||
let dump_len = payload.len().min(256);
|
||||
tracing::error!(
|
||||
"deserialization failed: {}. Raw bytes ({} of {} total): {:02x?}",
|
||||
e,
|
||||
dump_len,
|
||||
payload.len(),
|
||||
&payload[..dump_len]
|
||||
);
|
||||
Err(BridgeError::DeserializationWithDump(format!(
|
||||
"{} (payload {} bytes)",
|
||||
e,
|
||||
payload.len()
|
||||
)))
|
||||
}
|
||||
},
|
||||
Some(payload) => decode_inbound(&payload).map(Some),
|
||||
None => Err(BridgeError::Disconnected),
|
||||
}
|
||||
}
|
||||
|
||||
fn send_atlas_response(&self, resp: &AtlasLayerResponse) -> Result<(), BridgeError> {
|
||||
let payload = rmp_serde::to_vec_named(resp)?;
|
||||
let mut writer = self
|
||||
.writer
|
||||
.lock()
|
||||
.map_err(|e| BridgeError::MutexPoisoned(format!("writer: {}", e)))?;
|
||||
write_framed(writer.get_mut(), &payload)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for LocalBridge {
|
||||
|
||||
Reference in New Issue
Block a user