sunset_embassy/
embassy_channel.rs

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