1use core::fmt::{Debug, Display};
2use core::future::poll_fn;
3use core::mem;
4use core::pin::{Pin, pin};
5use core::sync::atomic::{AtomicBool, Ordering};
6use core::task::{Context, Poll, ready};
7
8use std::sync::{Arc, PoisonError};
9
10use bytes::{Buf as _, Bytes, BytesMut};
11use pin_project_lite::pin_project;
12use tokio::io::{AsyncBufRead, AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt as _};
13use tokio::select;
14use tokio::sync::{mpsc, oneshot};
15use tokio_stream::wrappers::ReceiverStream;
16use tokio_util::codec::Encoder;
17use tokio_util::io::StreamReader;
18use tokio_util::sync::PollSender;
19use tokio_util::task::AbortOnDropHandle;
20use tracing::{Instrument as _, Span, debug, error, instrument, trace};
21use wasm_tokio::{
22 AsyncReadCore as _, AsyncReadLeb128 as _, DEFAULT_MAX_INITIAL_CAPACITY, Leb128Encoder,
23};
24
25use crate::frame::MAX_INITIAL_PATH_CAPACITY;
26use crate::{copy_io_error, error_receiver_closed};
27
28mod client;
29mod server;
30
31pub use client::*;
32pub use server::*;
33
34pub enum HeaderReadError {
36 IO(std::io::Error),
38 UnsupportedVersion(u8),
40}
41
42impl Debug for HeaderReadError {
43 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
44 match self {
45 Self::IO(err) => Debug::fmt(err, f),
46 Self::UnsupportedVersion(v) => write!(f, "unsupported version byte: {v}"),
47 }
48 }
49}
50
51impl Display for HeaderReadError {
52 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
53 match self {
54 Self::IO(err) => Display::fmt(err, f),
55 Self::UnsupportedVersion(v) => write!(f, "unsupported version byte: {v}"),
56 }
57 }
58}
59
60impl core::error::Error for HeaderReadError {}
61
62#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
64pub struct Header {
65 pub instance: String,
67
68 pub name: String,
70}
71
72impl Header {
73 #[instrument(level = "trace", skip_all, ret(level = "trace"))]
79 pub async fn read(mut rx: impl AsyncRead + Unpin) -> Result<Self, HeaderReadError> {
80 let mut instance = String::default();
81 let mut name = String::default();
82 match rx.read_u8().await.map_err(HeaderReadError::IO)? {
83 0x00 => {
84 rx.read_core_name(&mut instance)
85 .await
86 .map_err(HeaderReadError::IO)?;
87 rx.read_core_name(&mut name)
88 .await
89 .map_err(HeaderReadError::IO)?;
90 }
91 v => return Err(HeaderReadError::UnsupportedVersion(v)),
92 }
93 Ok(Self { instance, name })
94 }
95}
96
97#[derive(Debug, Default)]
99enum IndexTrie {
100 #[default]
101 Empty,
102 Leaf {
103 tx: Option<mpsc::Sender<std::io::Result<Bytes>>>,
104 rx: Option<mpsc::Receiver<std::io::Result<Bytes>>>,
105 },
106 IndexNode {
107 tx: Option<mpsc::Sender<std::io::Result<Bytes>>>,
108 rx: Option<mpsc::Receiver<std::io::Result<Bytes>>>,
109 nested: Vec<Option<IndexTrie>>,
110 },
111 WildcardNode {
113 tx: Option<mpsc::Sender<std::io::Result<Bytes>>>,
114 rx: Option<mpsc::Receiver<std::io::Result<Bytes>>>,
115 nested: Option<Box<IndexTrie>>,
116 },
117}
118
119impl<'a>
120 From<(
121 &'a [Option<usize>],
122 mpsc::Sender<std::io::Result<Bytes>>,
123 Option<mpsc::Receiver<std::io::Result<Bytes>>>,
124 )> for IndexTrie
125{
126 fn from(
127 (path, tx, rx): (
128 &'a [Option<usize>],
129 mpsc::Sender<std::io::Result<Bytes>>,
130 Option<mpsc::Receiver<std::io::Result<Bytes>>>,
131 ),
132 ) -> Self {
133 match path {
134 [] => Self::Leaf { tx: Some(tx), rx },
135 [None, path @ ..] => Self::WildcardNode {
136 tx: None,
137 rx: None,
138 nested: Some(Box::new(Self::from((path, tx, rx)))),
139 },
140 [Some(i), path @ ..] => Self::IndexNode {
141 tx: None,
142 rx: None,
143 nested: {
144 let n = i.saturating_add(1);
145 let mut nested = Vec::with_capacity(n);
146 nested.resize_with(n, Option::default);
147 nested[*i] = Some(Self::from((path, tx, rx)));
148 nested
149 },
150 },
151 }
152 }
153}
154
155impl<'a>
156 From<(
157 &'a [Option<usize>],
158 mpsc::Sender<std::io::Result<Bytes>>,
159 mpsc::Receiver<std::io::Result<Bytes>>,
160 )> for IndexTrie
161{
162 fn from(
163 (path, tx, rx): (
164 &'a [Option<usize>],
165 mpsc::Sender<std::io::Result<Bytes>>,
166 mpsc::Receiver<std::io::Result<Bytes>>,
167 ),
168 ) -> Self {
169 Self::from((path, tx, Some(rx)))
170 }
171}
172
173impl<'a> From<(&'a [Option<usize>], mpsc::Sender<std::io::Result<Bytes>>)> for IndexTrie {
174 fn from((path, tx): (&'a [Option<usize>], mpsc::Sender<std::io::Result<Bytes>>)) -> Self {
175 Self::from((path, tx, None))
176 }
177}
178
179impl<P: AsRef<[Option<usize>]>> FromIterator<P> for IndexTrie {
180 fn from_iter<T: IntoIterator<Item = P>>(iter: T) -> Self {
181 let mut root = Self::Empty;
182 for path in iter {
183 let (tx, rx) = mpsc::channel(16);
184 if !root.insert(path.as_ref(), tx, Some(rx)) {
185 return Self::Empty;
186 }
187 }
188 root
189 }
190}
191
192impl IndexTrie {
193 fn for_each(
195 &mut self,
196 f: &mut impl FnMut(
197 &mut Option<mpsc::Sender<std::io::Result<Bytes>>>,
198 &mut Option<mpsc::Receiver<std::io::Result<Bytes>>>,
199 ),
200 ) {
201 match self {
202 Self::Empty => {}
203 Self::Leaf { tx, rx } => f(tx, rx),
204 Self::IndexNode { tx, rx, nested } => {
205 f(tx, rx);
206 for nested in nested.iter_mut().flatten() {
207 nested.for_each(f);
208 }
209 }
210 Self::WildcardNode { tx, rx, nested } => {
211 f(tx, rx);
212 if let Some(nested) = nested {
213 nested.for_each(f);
214 }
215 }
216 }
217 }
218
219 #[instrument(level = "trace", skip(self), ret(level = "trace"))]
221 fn close_rx(&mut self) -> bool {
222 let mut pending = false;
223 self.for_each(&mut |_, rx| {
224 pending |= rx.take().is_some_and(|rx| !rx.is_empty());
225 });
226 pending
227 }
228
229 #[instrument(level = "trace", skip(self), ret(level = "trace"))]
231 fn take_rx(&mut self, path: &[usize]) -> Option<mpsc::Receiver<std::io::Result<Bytes>>> {
232 let Some((i, path)) = path.split_first() else {
233 return match self {
234 Self::Empty => None,
235 Self::Leaf { rx, .. } => rx.take(),
236 Self::IndexNode { tx, rx, nested } => {
237 let rx = rx.take();
238 if nested.is_empty() && tx.is_none() {
239 *self = Self::Empty;
240 }
241 rx
242 }
243 Self::WildcardNode { tx, rx, nested } => {
244 let rx = rx.take();
245 if nested.is_none() && tx.is_none() {
246 *self = Self::Empty;
247 }
248 rx
249 }
250 };
251 };
252 match self {
253 Self::Empty | Self::Leaf { .. } | Self::WildcardNode { .. } => None,
254 Self::IndexNode { nested, .. } => nested
255 .get_mut(*i)
256 .and_then(|nested| nested.as_mut().and_then(|nested| nested.take_rx(path))),
257 }
262 }
263
264 #[instrument(level = "trace", skip(self), ret(level = "trace"))]
266 fn get_tx(&mut self, path: &[usize]) -> Option<mpsc::Sender<std::io::Result<Bytes>>> {
267 let Some((i, path)) = path.split_first() else {
268 return match self {
269 Self::Empty => None,
270 Self::Leaf { tx, .. } => tx.clone(),
271 Self::IndexNode { tx, .. } | Self::WildcardNode { tx, .. } => tx.clone(),
272 };
273 };
274 match self {
275 Self::Empty | Self::Leaf { .. } | Self::WildcardNode { .. } => None,
276 Self::IndexNode { nested, .. } => {
277 let nested = nested.get_mut(*i)?;
278 let nested = nested.as_mut()?;
279 nested.get_tx(path)
280 } }
285 }
286
287 #[instrument(level = "trace", skip(self), ret(level = "trace"))]
289 fn close_tx(&mut self) {
290 self.for_each(&mut |tx, _| {
291 tx.take();
292 });
293 }
294
295 #[instrument(level = "trace", skip(self, sender, receiver), ret(level = "trace"))]
298 fn insert(
299 &mut self,
300 path: &[Option<usize>],
301 sender: mpsc::Sender<std::io::Result<Bytes>>,
302 receiver: Option<mpsc::Receiver<std::io::Result<Bytes>>>,
303 ) -> bool {
304 match self {
305 Self::Empty => {
306 *self = Self::from((path, sender, receiver));
307 true
308 }
309 Self::Leaf { .. } => {
310 let Some((i, path)) = path.split_first() else {
311 return false;
312 };
313 let Self::Leaf { tx, rx } = mem::take(self) else {
314 return false;
315 };
316 if let Some(i) = i {
317 let n = i.saturating_add(1);
318 let mut nested = Vec::with_capacity(n);
319 nested.resize_with(n, Option::default);
320 nested[*i] = Some(Self::from((path, sender, receiver)));
321 *self = Self::IndexNode { tx, rx, nested };
322 } else {
323 *self = Self::WildcardNode {
324 tx,
325 rx,
326 nested: Some(Box::new(Self::from((path, sender, receiver)))),
327 };
328 }
329 true
330 }
331 Self::IndexNode { tx, rx, nested } => match (&tx, &rx, path) {
332 (None, None, []) => {
333 *tx = Some(sender);
334 *rx = receiver;
335 true
336 }
337 (_, _, [Some(i), path @ ..]) => {
338 let cap = i.saturating_add(1);
339 if nested.len() < cap {
340 nested.resize_with(cap, Option::default);
341 }
342 let nested = &mut nested[*i];
343 if let Some(nested) = nested {
344 nested.insert(path, sender, receiver)
345 } else {
346 *nested = Some(Self::from((path, sender, receiver)));
347 true
348 }
349 }
350 _ => false,
351 },
352 Self::WildcardNode { tx, rx, nested } => match (&tx, &rx, path) {
353 (None, None, []) => {
354 *tx = Some(sender);
355 *rx = receiver;
356 true
357 }
358 (_, _, [None, path @ ..]) => {
359 if let Some(nested) = nested {
360 nested.insert(path, sender, receiver)
361 } else {
362 *nested = Some(Box::new(Self::from((path, sender, receiver))));
363 true
364 }
365 }
366 _ => false,
367 },
368 }
369 }
370}
371
372pin_project! {
373 #[project = IncomingProj]
375 pub struct Incoming {
376 #[pin]
377 rx: Option<StreamReader<ReceiverStream<std::io::Result<Bytes>>, Bytes>>,
378 path: Arc<[usize]>,
379 io: Arc<IngressGuard>,
380 state: Arc<IngressState>,
381 }
382
383 impl PinnedDrop for Incoming {
384 fn drop(this: Pin<&mut Self>) {
385 let this = Pin::into_inner(this);
386 if let Some(rx) = this.rx.take() {
387 let (mut rx, chunk) = rx.into_inner_with_chunk();
388 rx.close();
389 if chunk.is_some() || !rx.as_ref().is_empty() {
390 this.mark_unprocessed();
391 }
392 }
393 }
394 }
395}
396
397impl Incoming {
398 pub fn new<T, P, Fut>(
404 mut rx: T,
405 paths: impl IntoIterator<Item = P>,
406 drain: bool,
407 on_ingress: impl FnOnce(T, std::io::Result<()>) -> Fut + Send + 'static,
408 ) -> Self
409 where
410 T: AsyncBufRead + Unpin + Send + 'static,
411 P: AsRef<[Option<usize>]>,
412 Fut: Future<Output = ()> + Send,
413 {
414 let (rx_tx, rx_rx) = mpsc::channel(128);
415 let state = Arc::new(IngressState {
416 index: std::sync::Mutex::new(paths.into_iter().collect()),
417 err: std::sync::OnceLock::default(),
418 unprocessed: AtomicBool::default(),
419 });
420 let (dropped_tx, dropped_rx) = drain.then(oneshot::channel).unzip();
421 let span = Span::current();
422 let task = tokio::spawn({
423 let state = Arc::clone(&state);
424 async move {
425 let res = async {
426 let mut io = pin!(async {
427 let res = ingress(&mut rx, &state.index, &rx_tx).await;
428 if let Err(err) = &res {
429 _ = state.err.set(copy_io_error(err));
430 }
431 drop(rx_tx);
432 trace!("shutting down index trie");
433 state
434 .index
435 .lock()
436 .unwrap_or_else(PoisonError::into_inner)
437 .close_tx();
438 res
439 });
440 let Some(mut dropped) = dropped_rx else {
441 return io.await;
442 };
443 select! {
444 biased;
445
446 res = &mut io => {
447 res?;
448 _ = dropped.await;
449 close_rx(&state)
450 }
451 _ = &mut dropped => {
452 close_rx(&state)?;
453 io.await
454 }
455 }
456 }
457 .await;
458 on_ingress(rx, res).await;
459 }
460 .instrument(span.clone())
461 });
462 Self {
463 rx: Some(StreamReader::new(ReceiverStream::new(rx_rx))),
464 path: Arc::from([]),
465 io: Arc::new(match dropped_tx {
466 Some(dropped) => IngressGuard::Drain { _dropped: dropped },
468 None => IngressGuard::Abort {
469 _task: AbortOnDropHandle::new(task),
470 },
471 }),
472 state,
473 }
474 }
475
476 pub(crate) fn mark_unprocessed(&self) {
479 trace!(path = ?self.path, "dropping handle with unprocessed data");
480 self.state.unprocessed.store(true, Ordering::Relaxed);
481 }
482
483 #[instrument(level = "trace", skip(self), fields(path = ?self.path))]
486 pub fn index(&self, path: &[usize]) -> std::io::Result<Self> {
487 if path.is_empty() {
488 return Err(std::io::Error::new(
489 std::io::ErrorKind::InvalidInput,
490 "path cannot be empty",
491 ));
492 }
493 let path = if self.path.is_empty() {
494 Arc::from(path)
495 } else {
496 Arc::from([self.path.as_ref(), path].concat())
497 };
498 trace!("locking index trie");
499 let mut index = self
500 .state
501 .index
502 .lock()
503 .map_err(|err| std::io::Error::other(err.to_string()))?;
504 trace!(?path, "taking index subscription");
505 let rx = index
506 .take_rx(&path)
507 .map(|rx| StreamReader::new(ReceiverStream::new(rx)));
508 Ok(Self {
509 rx,
510 path,
511 io: Arc::clone(&self.io),
512 state: Arc::clone(&self.state),
513 })
514 }
515}
516
517impl AsyncRead for Incoming {
518 #[instrument(level = "trace", skip_all, fields(path = ?self.path), ret(level = "trace"))]
519 fn poll_read(
520 mut self: Pin<&mut Self>,
521 cx: &mut Context<'_>,
522 buf: &mut tokio::io::ReadBuf<'_>,
523 ) -> Poll<std::io::Result<()>> {
524 if buf.remaining() == 0 {
525 return Poll::Ready(Ok(()));
526 }
527 trace!("reading");
528 let this = self.as_mut().project();
529 let Some(rx) = this.rx.as_pin_mut() else {
530 trace!("reader is closed");
531 return Poll::Ready(Ok(()));
532 };
533 ready!(rx.poll_read(cx, buf))?;
534 trace!(buf = ?buf.filled(), "read buffer");
535 if buf.filled().is_empty() {
536 self.rx.take();
537 if let Some(err) = self.state.err.get() {
538 return Poll::Ready(Err(copy_io_error(err)));
539 }
540 }
541 Poll::Ready(Ok(()))
542 }
543}
544
545struct IngressState {
546 index: std::sync::Mutex<IndexTrie>,
547 err: std::sync::OnceLock<std::io::Error>,
548 unprocessed: AtomicBool,
549}
550
551enum IngressGuard {
552 Abort { _task: AbortOnDropHandle<()> },
553 Drain { _dropped: oneshot::Sender<()> },
554}
555
556pub struct Outgoing {
558 tx: PollSender<(Bytes, Bytes)>,
559 path: Arc<[usize]>,
560 path_buf: Bytes,
561}
562
563impl Outgoing {
564 pub fn new<T, Fut>(
566 mut tx: T,
567 on_egress: impl FnOnce(T, std::io::Result<()>) -> Fut + Send + 'static,
568 ) -> Self
569 where
570 T: AsyncWrite + Unpin + Send + 'static,
571 Fut: Future<Output = ()> + Send,
572 {
573 let span = Span::current();
574 let (tx_tx, tx_rx) = mpsc::channel(128);
575 tokio::spawn(
576 async {
577 let res = egress(&mut tx, tx_rx).await;
578 on_egress(tx, res).await;
579 }
580 .instrument(span.clone()),
581 );
582 Self {
583 tx: PollSender::new(tx_tx),
584 path: Arc::from([]),
585 path_buf: Bytes::from_static(&[0]),
586 }
587 }
588
589 #[instrument(level = "trace", skip(self), fields(path = ?self.path))]
592 pub fn index(&self, path: &[usize]) -> std::io::Result<Self> {
593 if path.is_empty() {
594 return Err(std::io::Error::new(
595 std::io::ErrorKind::InvalidInput,
596 "path cannot be empty",
597 ));
598 }
599 let path: Arc<[usize]> = if self.path.is_empty() {
600 Arc::from(path)
601 } else {
602 Arc::from([self.path.as_ref(), path].concat())
603 };
604 let mut buf = BytesMut::with_capacity(path.len().saturating_add(5));
605 let n = u32::try_from(path.len())
606 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
607 trace!(n, "encoding path length");
608 Leb128Encoder.encode(n, &mut buf)?;
609 for p in path.as_ref() {
610 let p = u32::try_from(*p)
611 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
612 trace!(p, "encoding path element");
613 Leb128Encoder.encode(p, &mut buf)?;
614 }
615 Ok(Self {
616 tx: self.tx.clone(),
617 path,
618 path_buf: buf.freeze(),
619 })
620 }
621
622 pub(crate) fn poll_reserve(&mut self, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
623 self.tx
624 .poll_reserve(cx)
625 .map_err(|err| std::io::Error::new(std::io::ErrorKind::BrokenPipe, err))
626 }
627
628 pub(crate) async fn reserve(&mut self) -> std::io::Result<()> {
629 poll_fn(|cx| self.poll_reserve(cx)).await
630 }
631
632 pub(crate) fn send_reserved(&mut self, buf: Bytes) -> std::io::Result<()> {
633 trace!(path = ?self.path, ?buf, "sending outgoing frame");
634 self.tx
635 .send_item((self.path_buf.clone(), buf))
636 .map_err(|err| std::io::Error::new(std::io::ErrorKind::BrokenPipe, err))
637 }
638
639 pub async fn write_bytes(&mut self, buf: Bytes) -> std::io::Result<()> {
641 if buf.is_empty() {
642 return Ok(());
643 }
644 self.reserve().await?;
645 self.send_reserved(buf)
646 }
647}
648
649impl AsyncWrite for Outgoing {
650 #[instrument(level = "trace", skip_all, fields(path = ?self.path, buf = format!("{buf:02x?}")), ret(level = "trace"))]
651 fn poll_write(
652 mut self: Pin<&mut Self>,
653 cx: &mut Context<'_>,
654 buf: &[u8],
655 ) -> Poll<std::io::Result<usize>> {
656 if buf.is_empty() {
657 return Poll::Ready(Ok(0));
658 }
659 trace!("writing outgoing chunk");
660 ready!(self.poll_reserve(cx))?;
661 self.send_reserved(Bytes::copy_from_slice(buf))?;
662 Poll::Ready(Ok(buf.len()))
663 }
664
665 #[instrument(level = "trace", skip_all, fields(path = ?self.path), ret(level = "trace"))]
666 fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
667 Poll::Ready(Ok(()))
668 }
669
670 #[instrument(level = "trace", skip_all, fields(path = ?self.path), ret(level = "trace"))]
671 fn poll_shutdown(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
672 Poll::Ready(Ok(()))
673 }
674}
675
676#[instrument(level = "trace", skip_all, ret(level = "trace"))]
677async fn ingress(
678 mut rx: impl AsyncRead + Unpin,
679 index: &std::sync::Mutex<IndexTrie>,
680 param_tx: &mpsc::Sender<std::io::Result<Bytes>>,
681) -> std::io::Result<()> {
682 loop {
683 trace!("reading path length");
684 let b = match rx.read_u8().await {
685 Ok(b) => b,
686 Err(err) if err.kind() == std::io::ErrorKind::UnexpectedEof => return Ok(()),
687 Err(err) => return Err(err),
688 };
689 let n = AsyncReadExt::chain([b].as_slice(), &mut rx)
690 .read_u32_leb128()
691 .await?;
692 let n = usize::try_from(n)
693 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
694 trace!(n, "read path length");
695 let tx = if n == 0 {
696 param_tx
697 } else {
698 let mut path = Vec::with_capacity(n.min(MAX_INITIAL_PATH_CAPACITY));
699 for i in 0..n {
700 trace!(i, "reading path element");
701 let p = rx.read_u32_leb128().await?;
702 let p = usize::try_from(p)
703 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
704 path.push(p);
705 }
706 trace!(?path, "read path");
707
708 trace!("locking index trie");
709 let mut index = index
710 .lock()
711 .map_err(|err| std::io::Error::other(err.to_string()))?;
712 &index.get_tx(&path).ok_or_else(|| {
713 std::io::Error::new(
714 std::io::ErrorKind::NotFound,
715 format!("`{path:?}` subscription not found"),
716 )
717 })?
718 };
719 trace!("reading data length");
720 let n = rx.read_u32_leb128().await?;
721 trace!(n, "read data length");
722 let mut data = (&mut rx).take(n.into());
723 while data.limit() > 0 {
724 let k = usize::try_from(data.limit())
725 .unwrap_or(usize::MAX)
726 .min(DEFAULT_MAX_INITIAL_CAPACITY);
727 let mut buf = BytesMut::with_capacity(k);
728 trace!(len = k, "reading data chunk");
729 while buf.len() < k {
730 if data.read_buf(&mut buf).await? == 0 {
731 return Err(std::io::ErrorKind::UnexpectedEof.into());
732 }
733 }
734 trace!(?buf, "read data chunk");
735 tx.send(Ok(buf.freeze()))
736 .await
737 .map_err(|_| error_receiver_closed())?;
738 }
739 }
740}
741
742fn close_rx(state: &IngressState) -> std::io::Result<()> {
745 trace!("all handles dropped, closing index trie receivers");
746 let mut index = state.index.lock().unwrap_or_else(PoisonError::into_inner);
747 if index.close_rx() || state.unprocessed.load(Ordering::Relaxed) {
748 return Err(error_unprocessed());
749 }
750 Ok(())
751}
752
753fn error_unprocessed() -> std::io::Error {
755 std::io::Error::new(
756 std::io::ErrorKind::BrokenPipe,
757 "received data was not processed",
758 )
759}
760
761#[instrument(level = "trace", skip_all)]
762async fn egress(
763 mut tx: impl AsyncWrite + Unpin,
764 mut rx: mpsc::Receiver<(Bytes, Bytes)>,
765) -> std::io::Result<()> {
766 let mut buf = BytesMut::with_capacity(5);
767 trace!("waiting for next frame");
768 let mut next = rx.recv().await;
769 while let Some((path, data)) = next {
770 let data_len = u32::try_from(data.len())
771 .map_err(|err| std::io::Error::new(std::io::ErrorKind::InvalidInput, err))?;
772 buf.clear();
773 Leb128Encoder.encode(data_len, &mut buf)?;
774 let mut frame = path.chain(&mut buf).chain(data);
775 trace!(?frame, "writing egress frame");
776 tx.write_all_buf(&mut frame).await?;
777 next = match rx.try_recv() {
778 Ok(frame) => Some(frame),
779 Err(..) => {
780 tx.flush().await?;
781 trace!("waiting for next frame");
782 rx.recv().await
783 }
784 };
785 }
786 trace!("shutting down outgoing stream");
787 tx.shutdown().await
788}
789
790pub trait ConnHandler<Rx, Tx> {
795 const DRAIN: bool = true;
802
803 fn on_ingress(rx: Rx, res: std::io::Result<()>) -> impl Future<Output = ()> + Send {
805 _ = rx;
806 if let Err(err) = res {
807 error!(?err, "ingress failed");
808 } else {
809 debug!("ingress successfully complete");
810 }
811 async {}
812 }
813
814 fn on_egress(tx: Tx, res: std::io::Result<()>) -> impl Future<Output = ()> + Send {
816 _ = tx;
817 if let Err(err) = res {
818 error!(?err, "egress failed");
819 } else {
820 debug!("egress successfully complete");
821 }
822 async {}
823 }
824}
825
826impl<Rx, Tx> ConnHandler<Rx, Tx> for () {}
827
828#[cfg(test)]
829mod tests {
830 use core::time::Duration;
831
832 use std::io::ErrorKind;
833
834 use tokio::io::{BufReader, DuplexStream};
835
836 use super::*;
837
838 const FRAME: [u8; 4] = [0x01, 0x00, 0x01, 0x2a];
839
840 fn incoming(
841 drain: bool,
842 ) -> (
843 DuplexStream,
844 Incoming,
845 oneshot::Receiver<std::io::Result<()>>,
846 ) {
847 let (tx, rx) = tokio::io::duplex(16);
848 let (done_tx, done_rx) = oneshot::channel();
849 let rx = Incoming::new(BufReader::new(rx), [[Some(0)]], drain, |_, res| async {
850 _ = done_tx.send(res);
851 });
852 (tx, rx, done_rx)
853 }
854
855 async fn done(rx: oneshot::Receiver<std::io::Result<()>>) -> std::io::Result<()> {
856 tokio::time::timeout(Duration::from_secs(5), rx)
857 .await
858 .expect("ingress timed out")
859 .expect("ingress aborted")
860 }
861
862 async fn failed(rx: oneshot::Receiver<std::io::Result<()>>) -> ErrorKind {
863 done(rx).await.unwrap_err().kind()
864 }
865
866 #[test_log::test(tokio::test)]
867 async fn incoming_drop_aborts() {
868 let (_tx, rx, done_rx) = incoming(false);
869 drop(rx);
870 tokio::time::timeout(Duration::from_secs(5), done_rx)
871 .await
872 .unwrap()
873 .unwrap_err();
874 }
875
876 #[test_log::test(tokio::test)]
877 async fn incoming_drop_waits_for_eof() {
878 let (tx, rx, mut done_rx) = incoming(true);
879 drop(rx);
880 tokio::task::yield_now().await;
881 assert!(done_rx.try_recv().is_err());
882 drop(tx);
883 done(done_rx).await.unwrap();
884 }
885
886 #[test_log::test(tokio::test)]
887 async fn incoming_drop_accepts_empty_frame() {
888 let (mut tx, rx, done_rx) = incoming(true);
889 drop(rx);
890 tx.write_all(&[0x00, 0x00]).await.unwrap();
891 drop(tx);
892 done(done_rx).await.unwrap();
893 }
894
895 #[test_log::test(tokio::test)]
896 async fn incoming_drop_rejects_data() {
897 let (mut tx, rx, done_rx) = incoming(true);
898 drop(rx);
899 tx.write_all(&FRAME).await.unwrap();
900 assert_eq!(failed(done_rx).await, ErrorKind::BrokenPipe);
901 }
902
903 #[test_log::test(tokio::test)]
904 async fn incoming_drop_reports_ingress_error() {
905 let (mut tx, rx, done_rx) = incoming(true);
906 tx.write_all(&FRAME).await.unwrap();
907 tx.write_all(&[0x01, 0x01, 0x01, 0x2a]).await.unwrap();
908 drop(rx);
909 assert_eq!(failed(done_rx).await, ErrorKind::NotFound);
910 }
911
912 #[test_log::test(tokio::test)]
913 async fn incoming_drop_rejects_pending() {
914 let (mut tx, rx, done_rx) = incoming(true);
915 tx.write_all(&FRAME).await.unwrap();
916 tokio::task::yield_now().await;
917 drop(rx);
918 assert_eq!(failed(done_rx).await, ErrorKind::BrokenPipe);
919 }
920
921 #[test_log::test(tokio::test)]
922 async fn incoming_drop_rejects_unread() {
923 let (mut tx, rx, done_rx) = incoming(true);
924 let sub = rx.index(&[0]).unwrap();
925 tx.write_all(&FRAME).await.unwrap();
926 tokio::task::yield_now().await;
927 drop(sub);
928 drop(rx);
929 assert_eq!(failed(done_rx).await, ErrorKind::BrokenPipe);
930 }
931
932 #[test_log::test(tokio::test)]
933 async fn buffered_drop_rejects_unread() {
934 let (tx, rx, done_rx) = incoming(true);
935 drop(crate::BufferedIncoming {
936 buffer: BytesMut::from(&FRAME[..]),
937 inner: rx,
938 });
939 drop(tx);
940 assert_eq!(failed(done_rx).await, ErrorKind::BrokenPipe);
941 }
942
943 #[test_log::test(tokio::test)]
944 async fn incoming_eof_waits_for_drop() {
945 let (tx, mut rx, mut done_rx) = incoming(true);
946 drop(tx);
947 rx.read_to_end(&mut Vec::default()).await.unwrap();
948 assert!(done_rx.try_recv().is_err());
949 drop(rx);
950 done(done_rx).await.unwrap();
951 }
952
953 #[test_log::test(tokio::test)]
954 async fn incoming_eof_rejects_pending() {
955 let (mut tx, rx, done_rx) = incoming(true);
956 tx.write_all(&FRAME).await.unwrap();
957 drop(tx);
958 tokio::task::yield_now().await;
959 drop(rx);
960 assert_eq!(failed(done_rx).await, ErrorKind::BrokenPipe);
961 }
962
963 #[test_log::test(tokio::test)]
964 async fn ingress_truncated_path() {
965 let index = std::sync::Mutex::new(IndexTrie::Empty);
966 let (tx, _rx) = mpsc::channel(1);
967 let err = ingress([0x02, 0x00].as_slice(), &index, &tx)
968 .await
969 .unwrap_err();
970 assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
971 }
972
973 #[test_log::test(tokio::test)]
974 async fn ingress_chunked_data() {
975 let index = std::sync::Mutex::new(IndexTrie::Empty);
976 let (tx, mut rx) = mpsc::channel(4);
977 let n = DEFAULT_MAX_INITIAL_CAPACITY + 1;
978 let mut frame = vec![0x00, 0x81, 0x80, 0x40];
979 frame.resize(frame.len() + n, 0x42);
980 ingress(frame.as_slice(), &index, &tx).await.unwrap();
981 drop(tx);
982 let mut chunks = vec![];
983 while let Some(chunk) = rx.recv().await {
984 chunks.push(chunk.unwrap().len());
985 }
986 assert_eq!(chunks, [DEFAULT_MAX_INITIAL_CAPACITY, 1]);
987 }
988
989 #[test_log::test(tokio::test)]
990 async fn ingress_truncated_data() {
991 let index = std::sync::Mutex::new(IndexTrie::Empty);
992 let (tx, _rx) = mpsc::channel(1);
993 let err = ingress(
994 [0x00, 0xff, 0xff, 0xff, 0xff, 0x0f, 0x42].as_slice(),
995 &index,
996 &tx,
997 )
998 .await
999 .unwrap_err();
1000 assert_eq!(err.kind(), std::io::ErrorKind::UnexpectedEof);
1001 }
1002}