use asdf_overlay_common::{
ipc::{ClientRequest, Frame, ServerResponse, ServerToClientPacket},
request::Request,
};
use asdf_overlay_event::OverlayEvent;
use bincode::Encode;
use tokio::{
io::{AsyncReadExt, AsyncWriteExt, ReadHalf, split},
net::windows::named_pipe::NamedPipeServer,
sync::mpsc::{UnboundedSender, unbounded_channel},
};
pub struct IpcServerConn {
rx: ReadHalf<NamedPipeServer>,
buf: Vec<u8>,
chan: UnboundedSender<ServerToClientPacket>,
}
impl IpcServerConn {
pub async fn new(server: NamedPipeServer) -> anyhow::Result<Self> {
let (rx, mut tx) = split(server);
let (chan_tx, mut chan_rx) = unbounded_channel();
tokio::spawn({
async move {
let mut buf = Vec::new();
while let Some(packet) = chan_rx.recv().await {
bincode::encode_into_std_write(packet, &mut buf, bincode::config::standard())?;
Frame {
size: buf.len() as u32,
}
.write(&mut tx)
.await?;
tx.write_all(&buf).await?;
tx.flush().await?;
buf.clear();
}
Ok::<_, anyhow::Error>(())
}
});
Ok(Self {
rx,
buf: Vec::new(),
chan: chan_tx,
})
}
pub fn create_emitter(&self) -> IpcClientEventEmitter {
IpcClientEventEmitter {
inner: self.chan.clone(),
}
}
pub async fn recv(&mut self) -> anyhow::Result<(u32, Request)> {
let frame = Frame::read(&mut self.rx).await?;
self.buf.resize(frame.size as usize, 0_u8);
self.rx.read_exact(&mut self.buf).await?;
let packet: ClientRequest =
bincode::decode_from_slice(&self.buf, bincode::config::standard())?.0;
Ok((packet.id, packet.req))
}
pub fn reply(&mut self, id: u32, data: impl Encode) -> anyhow::Result<()> {
_ = self
.chan
.send(ServerToClientPacket::Response(ServerResponse {
id,
data: bincode::encode_to_vec(data, bincode::config::standard())?,
}));
Ok(())
}
}
#[derive(Clone)]
pub struct IpcClientEventEmitter {
inner: UnboundedSender<ServerToClientPacket>,
}
impl IpcClientEventEmitter {
pub fn emit(&self, event: OverlayEvent) -> anyhow::Result<()> {
self.inner.send(ServerToClientPacket::Event(event))?;
Ok(())
}
}