use std::sync::Arc;
use bytes::{Buf, BytesMut};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use crate::broker::backend_handle::DaemonProcess;
use crate::broker::backend_sdk::{BackendEndpointMux, LegacyClassification, MuxPoll};
use crate::broker::protocol::registry::SESSION_PAYLOAD_PROTOCOL;
use crate::containment::ContainedProcessGroup;
use crate::daemon::compile_session::session_takeover_from_buffered;
use crate::daemon::IntoDaemonAsyncListener;
pub async fn serve_backend_endpoint<L>(listener: L, identity: DaemonProcess) -> std::io::Result<()>
where
L: IntoDaemonAsyncListener,
{
let listener = listener.into_async_listener();
loop {
let stream = listener.accept().await?;
let identity = identity.clone();
tokio::spawn(async move {
if let Err(err) = serve_backend_connection(stream, &identity).await {
eprintln!("running-process-daemon: backend connection ended: {err}");
}
});
}
}
pub async fn serve_backend_connection<T>(mut io: T, identity: &DaemonProcess) -> std::io::Result<()>
where
T: AsyncRead + AsyncWrite + Unpin + Send + 'static,
{
let mux = BackendEndpointMux::new(identity.clone(), &[SESSION_PAYLOAD_PROTOCOL], |_buf| {
LegacyClassification::NotLegacy
});
let mut buf = BytesMut::new();
loop {
let verdict = mux
.poll(&buf)
.map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidData, err.to_string()))?;
match verdict {
MuxPoll::NeedMoreBytes => {
if io.read_buf(&mut buf).await? == 0 {
return Ok(());
}
}
MuxPoll::Legacy => {
return Err(std::io::Error::other(
"unexpected legacy-wire bytes on the SESSION backend endpoint",
));
}
MuxPoll::ProbeAnswered { reply, consumed } => {
io.write_all(&reply).await?;
io.flush().await?;
buf.advance(consumed);
}
MuxPoll::Payload { .. } => {
let group = Arc::new(ContainedProcessGroup::new()?);
session_takeover_from_buffered(io, buf, group).await?;
return Ok(());
}
}
}
}
#[cfg(test)]
mod tests;