asdf_overlay_client/
client.rs1use std::sync::{Arc, Weak};
6
7use anyhow::{Context as AnyhowContext, bail};
8use asdf_overlay_common::{
9 event::OverlayEvent,
10 ipc::{ClientRequest, Frame, ServerToClientPacket},
11 request::{
12 self, Request, Requestable,
13 surface::{SurfaceRequest, SurfaceRequestable},
14 window::{WindowRequest, WindowRequestable},
15 },
16};
17use dashmap::DashMap;
18use serde::de::DeserializeOwned;
19use tokio::{
20 io::{AsyncReadExt, AsyncWriteExt, WriteHalf, split},
21 net::windows::named_pipe::NamedPipeClient,
22 sync::{mpsc, oneshot},
23 task::JoinHandle,
24};
25
26pub struct IpcClientConn {
28 next_id: u32,
29 tx: WriteHalf<NamedPipeClient>,
30 buf: Vec<u8>,
31 map: Weak<DashMap<u32, oneshot::Sender<Vec<u8>>>>,
32 read_task: JoinHandle<anyhow::Result<()>>,
33}
34
35impl IpcClientConn {
36 pub async fn new(client: NamedPipeClient) -> anyhow::Result<(Self, IpcClientEventStream)> {
38 let (mut rx, tx) = split(client);
39
40 let map = Arc::new(DashMap::<u32, oneshot::Sender<Vec<u8>>>::new());
41 let (event_tx, event_rx) = mpsc::unbounded_channel();
42
43 let read_task = tokio::spawn({
44 let map = map.clone();
45
46 async move {
47 let mut buf = Vec::new();
48 loop {
49 let frame = Frame::read(&mut rx).await?;
50 buf.resize(frame.size as usize, 0_u8);
51 rx.read_exact(&mut buf).await?;
52
53 let packet: ServerToClientPacket = rmp_serde::from_slice(&buf)?;
54 match packet {
55 ServerToClientPacket::Response { id, payload } => {
56 if let Some((_, sender)) = map.remove(&id) {
57 _ = sender.send(payload);
58 }
59 }
60
61 ServerToClientPacket::Event(event) => {
62 let _ = event_tx.send(event);
63 }
64 }
65 }
66 }
67 });
68
69 let conn = IpcClientConn {
70 next_id: 0,
71 tx,
72 buf: vec![],
73 map: Arc::downgrade(&map),
74 read_task,
75 };
76
77 let stream = IpcClientEventStream { inner: event_rx };
78
79 Ok((conn, stream))
80 }
81
82 #[inline]
85 pub const fn window(&mut self, id: u32) -> IpcClientConnWindow<'_> {
86 IpcClientConnWindow { inner: self, id }
87 }
88
89 #[inline]
92 pub const fn surface(&mut self, id: u64) -> IpcClientConnSurface<'_> {
93 IpcClientConnSurface { inner: self, id }
94 }
95
96 pub async fn request<T: Requestable>(&mut self, req: T) -> Result<T::Response> {
99 self.request_inner::<T::Response>(req.into()).await
100 }
101
102 async fn request_inner<T: DeserializeOwned>(&mut self, req: Request) -> Result<T> {
103 let data = self
104 .send(req)
105 .await
106 .context("failed to send request")?
107 .await
108 .context("failed to receive response")?;
109
110 let res = rmp_serde::from_slice::<request::Result<T>>(&data)
111 .context("invalid response payload")?;
112 Ok(res.map_err(|err| request::Error::new(&err))?)
113 }
114
115 async fn send(&mut self, req: Request) -> Result<oneshot::Receiver<Vec<u8>>> {
118 let Some(map) = self.map.upgrade() else {
119 bail!("connection closed");
120 };
121
122 let id = self.next_id;
123 self.next_id += 1;
124
125 self.buf.clear();
126 rmp_serde::encode::write(&mut self.buf, &ClientRequest { id, req })?;
127 Frame {
128 size: self.buf.len() as _,
129 }
130 .write(&mut self.tx)
131 .await?;
132
133 let (tx, rx) = oneshot::channel();
134 map.insert(id, tx);
135 self.tx.write_all(&self.buf).await?;
136
137 self.tx.flush().await?;
138 Ok(rx)
139 }
140}
141
142impl Drop for IpcClientConn {
143 fn drop(&mut self) {
144 self.read_task.abort();
145 }
146}
147
148pub type Result<T> = core::result::Result<T, anyhow::Error>;
150
151#[derive(Debug, thiserror::Error)]
153pub enum Error {
154 #[error("ipc io error")]
155 Io(
156 #[from]
157 #[source]
158 anyhow::Error,
159 ),
160
161 #[error("request failed")]
162 Request(#[from] request::Error),
163}
164
165pub struct IpcClientConnWindow<'a> {
167 inner: &'a mut IpcClientConn,
168 id: u32,
169}
170
171impl IpcClientConnWindow<'_> {
172 pub async fn request<T: WindowRequestable>(&mut self, req: T) -> anyhow::Result<T::Response> {
174 self.inner
175 .request_inner::<T::Response>(Request::Window(WindowRequest {
176 id: self.id,
177 kind: req.into(),
178 }))
179 .await
180 }
181}
182pub struct IpcClientConnSurface<'a> {
184 inner: &'a mut IpcClientConn,
185 id: u64,
186}
187
188impl IpcClientConnSurface<'_> {
189 pub async fn request<T: SurfaceRequestable>(&mut self, req: T) -> anyhow::Result<T::Response> {
191 self.inner
192 .request_inner::<T::Response>(Request::Surface(SurfaceRequest {
193 id: self.id,
194 kind: req.into(),
195 }))
196 .await
197 }
198}
199
200pub struct IpcClientEventStream {
202 inner: mpsc::UnboundedReceiver<OverlayEvent>,
203}
204
205impl IpcClientEventStream {
206 #[inline]
209 pub async fn recv(&mut self) -> Option<OverlayEvent> {
210 self.inner.recv().await
211 }
212}