sunset_async/
async_channel.rs

1//! Presents SSH channels as async
2use core::future::poll_fn;
3
4#[allow(unused_imports)]
5use log::{debug, error, info, log, trace, warn};
6
7use embedded_io_async::{ErrorType, Read, Write};
8
9use crate::*;
10use sunset::{ChanData, ChanNum, Result};
11
12/// Common implementation
13struct ChanIO<'g> {
14    num: ChanNum,
15    dt: ChanData,
16    sunset: &'g dyn async_sunset::ChanCore,
17}
18
19impl core::fmt::Debug for ChanIO<'_> {
20    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
21        f.debug_struct("ChanIO")
22            .field("num", &self.num)
23            .field("dt", &self.dt)
24            .finish_non_exhaustive()
25    }
26}
27
28impl ChanIO<'_> {
29    pub async fn until_closed(&self) -> Result<()> {
30        poll_fn(|cx| self.sunset.poll_until_channel_closed(cx, self.num)).await
31    }
32}
33
34impl Drop for ChanIO<'_> {
35    fn drop(&mut self) {
36        self.sunset.dec_chan(self.num)
37    }
38}
39
40impl Clone for ChanIO<'_> {
41    fn clone(&self) -> Self {
42        self.sunset.inc_chan(self.num);
43        Self { num: self.num, dt: self.dt, sunset: self.sunset }
44    }
45}
46
47impl ErrorType for ChanIO<'_> {
48    type Error = sunset::Error;
49}
50
51impl Read for ChanIO<'_> {
52    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, sunset::Error> {
53        poll_fn(|cx| self.sunset.poll_read_channel(cx, self.num, self.dt, buf)).await
54    }
55}
56
57impl Write for ChanIO<'_> {
58    async fn write(&mut self, buf: &[u8]) -> Result<usize, sunset::Error> {
59        poll_fn(|cx| self.sunset.poll_write_channel(cx, self.num, self.dt, buf))
60            .await
61    }
62
63    // TODO: not sure how easy end-to-end flush is
64    // async fn flush(&mut self) -> Result<(), Self::Error> {
65    // }
66}
67
68// Public wrappers for In only
69
70/// A standard bidirectional SSH channel
71#[derive(Debug)]
72pub struct ChanInOut<'g>(ChanIO<'g>);
73
74// Manual Clone since derive requires template parameters impl Clone.
75impl Clone for ChanInOut<'_> {
76    fn clone(&self) -> Self {
77        Self(self.0.clone())
78    }
79}
80
81/// An input-only SSH channel, such as stderr for a client
82#[derive(Debug, Clone)]
83pub struct ChanIn<'g>(ChanIO<'g>);
84
85#[derive(Debug, Clone)]
86/// An output-only SSH channel, such as stderr for a server
87pub struct ChanOut<'g>(ChanIO<'g>);
88
89impl<'g> ChanInOut<'g> {
90    // caller must have already incremented the refcount
91    pub(crate) fn new(
92        num: ChanNum,
93        dt: ChanData,
94        sunset: &'g dyn async_sunset::ChanCore,
95    ) -> Self {
96        Self(ChanIO { num, dt, sunset })
97    }
98
99    /// A future that waits until the channel closes
100    pub async fn until_closed(&self) -> Result<()> {
101        self.0.until_closed().await
102    }
103
104    /// Send a terminal size change notification
105    ///
106    /// Only applicable to client shell channels with a PTY
107    pub async fn term_window_change(
108        &self,
109        winch: sunset::packets::WinChange,
110    ) -> Result<()> {
111        poll_fn(|cx| self.0.sunset.poll_term_window_change(cx, self.0.num, &winch))
112            .await
113    }
114}
115
116impl<'g> ChanIn<'g> {
117    // caller must have already incremented the refcount
118    pub(crate) fn new(
119        num: ChanNum,
120        dt: ChanData,
121        sunset: &'g dyn async_sunset::ChanCore,
122    ) -> Self {
123        Self(ChanIO { num, dt, sunset })
124    }
125}
126
127impl<'g> ChanOut<'g> {
128    // caller must have already incremented the refcount
129    pub(crate) fn new(
130        num: ChanNum,
131        dt: ChanData,
132        sunset: &'g dyn async_sunset::ChanCore,
133    ) -> Self {
134        Self(ChanIO { num, dt, sunset })
135    }
136
137    /// A future that waits until the channel closes
138    pub async fn until_closed(&self) -> Result<()> {
139        self.0.until_closed().await
140    }
141}
142
143impl ErrorType for ChanInOut<'_> {
144    type Error = sunset::Error;
145}
146
147impl ErrorType for ChanIn<'_> {
148    type Error = sunset::Error;
149}
150
151impl ErrorType for ChanOut<'_> {
152    type Error = sunset::Error;
153}
154
155impl Read for ChanInOut<'_> {
156    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, sunset::Error> {
157        self.0.read(buf).await
158    }
159}
160
161impl Write for ChanInOut<'_> {
162    async fn write(&mut self, buf: &[u8]) -> Result<usize, sunset::Error> {
163        self.0.write(buf).await
164    }
165}
166
167impl Read for ChanIn<'_> {
168    async fn read(&mut self, buf: &mut [u8]) -> Result<usize, sunset::Error> {
169        self.0.read(buf).await
170    }
171}
172
173impl Write for ChanOut<'_> {
174    async fn write(&mut self, buf: &[u8]) -> Result<usize, sunset::Error> {
175        self.0.write(buf).await
176    }
177}