use std::sync::Arc;
use tokio::sync::mpsc;
use crate::instrument;
use crate::runtime::Runtime;
use crate::{RemoteInvocation, RemoteResponse, ResponseRegistry};
use super::framing::{self, FrameCodec, StreamInit};
use super::net::{Net, RecvHalf};
pub async fn run_actor_stream_writer(
net: Arc<dyn Net>,
runtime: Arc<dyn Runtime>,
remote_node_id: String,
actor_label: String,
mut invocation_rx: mpsc::UnboundedReceiver<RemoteInvocation>,
response_registry: ResponseRegistry,
) {
let (mut send, recv) = match net.open_actor_stream(&remote_node_id).await {
Ok(streams) => {
instrument::stream_opened();
streams
}
Err(e) => {
tracing::error!(
"Failed to open actor stream to {remote_node_id} for {actor_label}: {e}"
);
response_registry.fail_all(&format!("connection to {remote_node_id} unavailable: {e}"));
return;
}
};
let init = StreamInit {
actor_label: actor_label.clone(),
};
let frame = match framing::encode_message(&init) {
Ok(f) => f,
Err(e) => {
tracing::error!("Failed to encode StreamInit: {e}");
response_registry.fail_all(&format!("StreamInit encode failed: {e}"));
return;
}
};
if let Err(e) = send.write_all(&frame).await {
tracing::error!("Failed to send StreamInit for {actor_label}: {e}");
response_registry.fail_all(&format!("StreamInit send failed: {e}"));
return;
}
let registry_clone = response_registry.clone();
let label_clone = actor_label.clone();
let reader_handle = runtime.spawn(Box::pin(async move {
read_responses(recv, registry_clone, label_clone).await;
}));
while let Some(invocation) = invocation_rx.recv().await {
let frame = framing::encode_invocation_frame(
invocation.call_id,
&invocation.message_type,
&invocation.payload,
);
instrument::network_bytes_sent(frame.len() as u64);
if let Err(e) = send.write_all(&frame).await {
tracing::error!("Actor stream write failed for {actor_label}: {e} — closing stream");
break;
}
}
let _ = send.finish();
reader_handle.abort();
response_registry.fail_all(&format!(
"actor stream to {remote_node_id} for {actor_label} closed"
));
instrument::stream_closed();
tracing::debug!("Actor stream writer for {actor_label} on {remote_node_id} closed");
}
async fn read_responses(
mut recv: Box<dyn RecvHalf>,
response_registry: ResponseRegistry,
actor_label: String,
) {
let mut codec = FrameCodec::new();
let close_reason = match super::net::pump_frames(
recv.as_mut(),
&mut codec,
|n| instrument::network_bytes_received(n as u64),
|frame| {
match framing::decode_response_frame(&frame) {
Ok(decoded) => response_registry.complete(RemoteResponse {
call_id: decoded.call_id,
result: decoded.result.map(|bytes| bytes.to_vec()),
}),
Err(e) => tracing::warn!("Failed to decode response for {actor_label}: {e}"),
}
std::ops::ControlFlow::Continue(())
},
)
.await
{
Ok(()) => {
tracing::debug!("Response stream for {actor_label} closed");
"response stream closed by peer".to_string()
}
Err(e) => {
tracing::error!("Response stream read error for {actor_label}: {e}");
format!("response stream error: {e}")
}
};
response_registry.fail_all(&close_reason);
}