1use std::pin::Pin;
2use futures_util::{AsyncRead, AsyncWrite};
3use pin_project::pin_project;
4use std::task::{Context, Poll};
5use async_trait::async_trait;
6use sillad::{dialer::Dialer, listener::Listener, Pipe};
7
8#[pin_project]
9pub struct HexPipe<P: Pipe> {
10 #[pin]
11 inner: P,
12 read_buf: Vec<u8>,
13 leftover: Vec<u8>,
14}
15
16impl<P: Pipe> HexPipe<P> {
17 pub fn new(inner: P) -> Self {
18 Self { inner, read_buf: Vec::new(), leftover: Vec::new() }
19 }
20}
21
22impl<P: Pipe> AsyncRead for HexPipe<P> {
23 fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<std::io::Result<usize>> {
24 let mut this = self.project();
25 if !this.read_buf.is_empty() {
26 let n = buf.len().min(this.read_buf.len());
27 buf[..n].copy_from_slice(&this.read_buf[..n]);
28 this.read_buf.drain(..n);
29 return Poll::Ready(Ok(n));
30 }
31 let mut tmp = [0u8; 4096];
32 match Pin::new(&mut this.inner).poll_read(cx, &mut tmp) {
33 Poll::Ready(Ok(0)) => {
34 if this.leftover.is_empty() {
35 Poll::Ready(Ok(0))
36 } else {
37 Poll::Ready(Err(std::io::Error::new(std::io::ErrorKind::UnexpectedEof, "incomplete hex")))
38 }
39 }
40 Poll::Ready(Ok(n)) => {
41 this.leftover.extend_from_slice(&tmp[..n]);
42 let decode_len = this.leftover.len() / 2 * 2;
43 let decoded = match hex::decode(&this.leftover[..decode_len]) {
44 Ok(v) => v,
45 Err(_) => return Poll::Ready(Err(std::io::Error::new(std::io::ErrorKind::InvalidData, "bad hex"))),
46 };
47 this.read_buf.extend_from_slice(&decoded);
48 this.leftover.drain(..decode_len);
49 let n = buf.len().min(this.read_buf.len());
50 buf[..n].copy_from_slice(&this.read_buf[..n]);
51 this.read_buf.drain(..n);
52 Poll::Ready(Ok(n))
53 }
54 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
55 Poll::Pending => Poll::Pending,
56 }
57 }
58}
59
60impl<P: Pipe> AsyncWrite for HexPipe<P> {
61 fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<std::io::Result<usize>> {
62 let mut this = self.project();
63 let encoded = hex::encode(buf);
64 this.inner.as_mut().poll_write(cx, encoded.as_bytes()).map_ok(|_| buf.len())
65 }
66
67 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
68 let mut this = self.project();
69 this.inner.as_mut().poll_flush(cx)
70 }
71
72 fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
73 let mut this = self.project();
74 this.inner.as_mut().poll_close(cx)
75 }
76}
77
78impl<P: Pipe> Pipe for HexPipe<P> {
79 fn shared_secret(&self) -> Option<&[u8]> { self.inner.shared_secret() }
80 fn protocol(&self) -> &str { "hex" }
81 fn remote_addr(&self) -> Option<&str> { self.inner.remote_addr() }
82}
83
84pub struct HexDialer<D: Dialer> { pub inner: D }
85
86#[async_trait]
87impl<D: Dialer> Dialer for HexDialer<D> {
88 type P = HexPipe<D::P>;
89 async fn dial(&self) -> std::io::Result<Self::P> { self.inner.dial().await.map(HexPipe::new) }
90}
91
92pub struct HexListener<L: Listener> { pub inner: L }
93
94#[async_trait]
95impl<L: Listener> Listener for HexListener<L> {
96 type P = HexPipe<L::P>;
97 async fn accept(&mut self) -> std::io::Result<Self::P> { self.inner.accept().await.map(HexPipe::new) }
98}