1use std::path::Path;
4use std::sync::Arc;
5
6use microsandbox_protocol::codec;
7use tokio::sync::{mpsc, oneshot};
8use tokio::task::JoinHandle;
9use tokio::time::Instant;
10use zeroize::{Zeroize, Zeroizing};
11
12use crate::router::{self, Lease, State, WriteCommand};
13use crate::{
14 ByteTransport, ClientError, ClientResult, ConnectOptions, Connector, Delivery, ErrorKind,
15 Established, IntoOutboundMessage, LocalConnector, Message, Protocol, RawFrame, RawStream,
16 Request, RequestOptions, Stream,
17};
18
19pub struct Client<P: Protocol> {
25 pub(crate) inner: Arc<Owner<P>>,
26}
27
28pub(crate) struct Owner<P: Protocol> {
29 pub(crate) state: Arc<State>,
30 pub(crate) ready: P::Ready,
31 pub(crate) codec: Arc<dyn crate::EnvelopeCodec>,
32 writer: mpsc::Sender<WriteCommand>,
33 handles: Vec<JoinHandle<()>>,
34}
35
36enum Packet {
37 Frame(RawFrame),
38 Exact(Zeroizing<Vec<u8>>),
39}
40
41impl<P: Protocol> Client<P> {
46 pub async fn connect(path: impl AsRef<Path>) -> ClientResult<Self> {
48 Self::connect_with(path, |options| options).await
49 }
50
51 pub async fn connect_with(
53 path: impl AsRef<Path>,
54 configure: impl FnOnce(ConnectOptions) -> ConnectOptions,
55 ) -> ClientResult<Self> {
56 Self::connect_connector_with(&LocalConnector::new(path), configure).await
57 }
58
59 pub async fn connect_connector(connector: &dyn Connector) -> ClientResult<Self> {
61 Self::connect_connector_with(connector, |options| options).await
62 }
63
64 pub async fn connect_connector_with(
66 connector: &dyn Connector,
67 configure: impl FnOnce(ConnectOptions) -> ConnectOptions,
68 ) -> ClientResult<Self> {
69 let options = configure(ConnectOptions::default());
70 options.limits.validate()?;
71 let deadline = crate::options::checked_deadline(options.setup_timeout)?;
72 if deadline <= Instant::now() {
73 return Err(ClientError::new(ErrorKind::Timeout));
74 }
75 tokio::time::timeout_at(deadline, async {
76 let stream = connector.connect(deadline).await?;
77 let established = P::establish(stream, options).await?;
78 Self::from_established(established).await
79 })
80 .await
81 .map_err(|_| ClientError::new(ErrorKind::Timeout))?
82 }
83
84 pub async fn connect_stream(stream: impl ByteTransport) -> ClientResult<Self> {
86 Self::connect_stream_with(stream, |options| options).await
87 }
88
89 pub async fn connect_stream_with(
91 stream: impl ByteTransport,
92 configure: impl FnOnce(ConnectOptions) -> ConnectOptions,
93 ) -> ClientResult<Self> {
94 let options = configure(ConnectOptions::default());
95 options.limits.validate()?;
96 let deadline = crate::options::checked_deadline(options.setup_timeout)?;
97 if deadline <= Instant::now() {
98 return Err(ClientError::new(ErrorKind::Timeout));
99 }
100 tokio::time::timeout_at(deadline, async {
101 let established = P::establish(Box::new(stream), options).await?;
102 Self::from_established(established).await
103 })
104 .await
105 .map_err(|_| ClientError::new(ErrorKind::Timeout))?
106 }
107
108 pub async fn from_established(established: Established<P::Ready>) -> ClientResult<Self> {
110 established.ids.validate()?;
111 established.limits.validate()?;
112 let state = State::new(established.ids, established.limits, P::REUSE_IDS);
113 let (reader, writer) = tokio::io::split(established.transport);
114 let (sender, queue) = mpsc::channel(state.limits.queued_writes);
115 let handles = vec![
118 tokio::spawn(router::reader_loop(reader, Arc::clone(&state))),
119 tokio::spawn(router::writer_loop(writer, queue, Arc::clone(&state))),
120 ];
121 Ok(Self {
122 inner: Arc::new(Owner {
123 state,
124 ready: established.ready,
125 codec: established.codec,
126 writer: sender,
127 handles,
128 }),
129 })
130 }
131
132 pub fn ready(&self) -> &P::Ready {
134 &self.inner.ready
135 }
136
137 pub fn is_closed(&self) -> bool {
139 self.inner.state.is_closed()
140 }
141
142 pub async fn closed(&self) {
145 self.inner.state.cancelled().await;
146 }
147
148 pub async fn close(&self) {
150 self.inner.state.close(ErrorKind::Closed);
151 for handle in &self.inner.handles {
152 handle.abort();
153 }
154 }
155
156 pub async fn request<M: IntoOutboundMessage<P>>(&self, message: M) -> ClientResult<Message> {
158 self.request_with(message, |options| options).await
159 }
160
161 pub async fn request_with<M: IntoOutboundMessage<P>>(
163 &self,
164 message: M,
165 configure: impl FnOnce(RequestOptions) -> RequestOptions,
166 ) -> ClientResult<Message> {
167 let outbound = message.into_outbound(self.ready(), self.inner.codec.as_ref())?;
168 let frame = self
169 .request_raw_with(outbound.flags, outbound.body, configure)
170 .await?;
171 self.inner
172 .codec
173 .decode(frame)
174 .map_err(|error| error.with_delivery(Delivery::Unknown))
175 }
176
177 pub async fn request_typed<R: Request<P>>(&self, request: &R) -> Result<R::Response, R::Error> {
179 self.request_typed_with(request, |options| options).await
180 }
181
182 pub async fn request_typed_with<R: Request<P>>(
184 &self,
185 request: &R,
186 configure: impl FnOnce(RequestOptions) -> RequestOptions,
187 ) -> Result<R::Response, R::Error> {
188 let message = self.request_with(request.message()?, configure).await?;
189 if message.flags & microsandbox_protocol::message::FLAG_TERMINAL == 0 {
190 return Err(ClientError::new(ErrorKind::InvalidData)
191 .with_delivery(Delivery::Unknown)
192 .into());
193 }
194 request.decode(message)
195 }
196
197 pub async fn stream<M: IntoOutboundMessage<P>>(&self, message: M) -> ClientResult<Stream<P>> {
199 self.stream_with(message, |options| options).await
200 }
201
202 pub async fn stream_with<M: IntoOutboundMessage<P>>(
204 &self,
205 message: M,
206 configure: impl FnOnce(RequestOptions) -> RequestOptions,
207 ) -> ClientResult<Stream<P>> {
208 let outbound = message.into_outbound(self.ready(), self.inner.codec.as_ref())?;
209 Ok(Stream::from_raw(
210 self.stream_raw_with(outbound.flags, outbound.body, configure)
211 .await?,
212 ))
213 }
214
215 pub async fn request_raw(&self, flags: u8, body: Vec<u8>) -> ClientResult<RawFrame> {
217 self.request_raw_with(flags, body, |options| options).await
218 }
219
220 pub async fn request_raw_with(
222 &self,
223 flags: u8,
224 body: Vec<u8>,
225 configure: impl FnOnce(RequestOptions) -> RequestOptions,
226 ) -> ClientResult<RawFrame> {
227 let packet = self.packet(0, flags, body)?;
228 let mut stream = self.reserve_stream()?;
229 let lease = Arc::clone(&stream.receiver.lease);
230 let options = configure(RequestOptions::default());
231 self.attempt(&lease, options, async {
232 self.write_opening(&lease, packet).await?;
233 stream
234 .recv()
235 .await?
236 .ok_or_else(|| ClientError::new(ErrorKind::PeerClosed))
237 })
238 .await
239 }
242
243 pub async fn stream_raw(&self, flags: u8, body: Vec<u8>) -> ClientResult<RawStream<P>> {
245 self.stream_raw_with(flags, body, |options| options).await
246 }
247
248 pub async fn stream_raw_with(
250 &self,
251 flags: u8,
252 body: Vec<u8>,
253 configure: impl FnOnce(RequestOptions) -> RequestOptions,
254 ) -> ClientResult<RawStream<P>> {
255 let packet = self.packet(0, flags, body)?;
256 let stream = self.reserve_stream()?;
257 let lease = Arc::clone(&stream.receiver.lease);
258 let options = configure(RequestOptions::default());
259 self.attempt(&lease, options, self.write_opening(&lease, packet))
260 .await?;
261 Ok(stream)
262 }
263
264 pub async fn send<M: IntoOutboundMessage<P>>(&self, id: u32, message: M) -> ClientResult<()> {
266 let lease = self.inner.state.owned(id)?;
267 self.send_owned(&lease, message).await
268 }
269
270 pub async fn send_raw(&self, id: u32, flags: u8, body: &[u8]) -> ClientResult<()> {
272 let lease = self.inner.state.owned(id)?;
273 self.send_raw_owned(&lease, flags, body).await
274 }
275
276 pub async fn write_unchecked(&self, packet: Vec<u8>) -> ClientResult<()> {
279 if packet.len() > self.inner.state.limits.buffered_bytes as usize {
280 return Err(ClientError::new(ErrorKind::Capacity));
281 }
282 self.write_packet(None, Packet::Exact(Zeroizing::new(packet)))
283 .await
284 }
285
286 pub(crate) async fn send_owned<M: IntoOutboundMessage<P>>(
287 &self,
288 lease: &Arc<Lease>,
289 message: M,
290 ) -> ClientResult<()> {
291 let outbound = message.into_outbound(self.ready(), self.inner.codec.as_ref())?;
292 self.write_packet(
293 Some(lease),
294 self.packet(lease.id, outbound.flags, outbound.body)?,
295 )
296 .await
297 }
298
299 pub(crate) async fn send_raw_owned(
300 &self,
301 lease: &Arc<Lease>,
302 flags: u8,
303 body: &[u8],
304 ) -> ClientResult<()> {
305 self.write_packet(Some(lease), self.packet(lease.id, flags, body.to_vec())?)
306 .await
307 }
308
309 fn reserve_stream(&self) -> ClientResult<RawStream<P>> {
310 let (lease, receiver) = self.inner.state.reserve()?;
311 Ok(RawStream::new(self.clone(), lease, receiver))
312 }
313
314 fn packet(&self, id: u32, flags: u8, body: Vec<u8>) -> ClientResult<Packet> {
315 if body.len() > self.inner.state.limits.max_frame_size as usize - 5 {
316 return Err(ClientError::new(ErrorKind::Capacity));
317 }
318 Ok(Packet::Frame(RawFrame { id, flags, body }))
319 }
320
321 async fn write_opening(&self, lease: &Arc<Lease>, mut packet: Packet) -> ClientResult<()> {
322 let Packet::Frame(frame) = &mut packet else {
323 unreachable!()
324 };
325 frame.id = lease.id;
326 self.write_packet(Some(lease), packet).await
327 }
328
329 async fn write_packet(&self, lease: Option<&Arc<Lease>>, packet: Packet) -> ClientResult<()> {
330 let bytes = Arc::clone(&self.inner.state.budget)
331 .acquire_many_owned(packet.len() as u32)
332 .await
333 .map_err(|_| self.inner.state.error())?;
334 let permit = self
335 .inner
336 .writer
337 .reserve()
338 .await
339 .map_err(|_| self.inner.state.error())?;
340 let packet = packet.encode()?;
344 let (ack, written) = oneshot::channel();
345 self.inner.state.admit(
346 lease,
347 permit,
348 WriteCommand {
349 packet,
350 ack,
351 _bytes: bytes,
352 },
353 )?;
354 written
355 .await
356 .map_err(|_| self.inner.state.error().with_delivery(Delivery::Unknown))?
357 }
358
359 async fn attempt<T>(
360 &self,
361 lease: &Lease,
362 options: RequestOptions,
363 future: impl std::future::Future<Output = ClientResult<T>>,
364 ) -> ClientResult<T> {
365 let result = match options
366 .request_timeout
367 .or(self.inner.state.limits.request_timeout)
368 {
369 Some(timeout) => {
370 let deadline = crate::options::checked_deadline(timeout)?;
371 if deadline <= Instant::now() {
375 Err(ClientError::new(ErrorKind::Timeout))
376 } else {
377 tokio::time::timeout_at(deadline, future)
378 .await
379 .unwrap_or_else(|_| Err(ClientError::new(ErrorKind::Timeout)))
380 }
381 }
382 None => future.await,
383 };
384 result.map_err(|error| error.with_delivery(lease.delivery()))
385 }
386}
387
388impl Packet {
389 fn len(&self) -> usize {
390 match self {
391 Self::Frame(frame) => frame.body.len() + 9,
392 Self::Exact(packet) => packet.len(),
393 }
394 }
395
396 fn encode(self) -> ClientResult<Zeroizing<Vec<u8>>> {
397 match self {
398 Self::Exact(packet) => Ok(packet),
399 Self::Frame(mut frame) => {
400 let mut packet = Zeroizing::new(Vec::with_capacity(frame.body.len() + 9));
401 let result = codec::encode_raw_to_buf(&frame, &mut packet);
402 frame.body.zeroize();
403 result.map_err(|_| ClientError::new(ErrorKind::InvalidData))?;
404 Ok(packet)
405 }
406 }
407 }
408}
409
410impl<P: Protocol> Clone for Client<P> {
415 fn clone(&self) -> Self {
416 Self {
417 inner: Arc::clone(&self.inner),
418 }
419 }
420}
421
422impl<P: Protocol> Drop for Owner<P> {
423 fn drop(&mut self) {
424 self.state.close(ErrorKind::Closed);
425 for handle in &self.handles {
426 handle.abort();
427 }
428 }
429}