sunset_embassy/server.rs
1use embedded_io_async::{Read, Write};
2
3use sunset::*;
4
5use crate::*;
6use embassy_sunset::EmbassySunset;
7
8/// An async SSH server instance
9///
10/// The [`run()`][Self::run] method runs the session to completion, with application behaviour
11/// defined by the [`ServBehaviour`] instance.
12///
13/// Once the client has opened sessions, those can be retrieved with [`stdio()`][Self::stdio]
14/// and [`stdio_stderr()`][Self::stdio_stderr] methods.
15///
16/// This is async executor agnostic, though requires the `ServBehaviour` instance
17/// to be wrapped in a [`SunsetMutex`].
18pub struct SSHServer<'a> {
19 sunset: EmbassySunset<'a>,
20}
21
22impl<'a> SSHServer<'a> {
23 // May return an error if RNG fails
24 pub fn new(inbuf: &'a mut [u8], outbuf: &'a mut [u8],
25 ) -> Result<Self> {
26 let runner = Runner::new_server(inbuf, outbuf)?;
27 let sunset = EmbassySunset::new(runner);
28 Ok(Self { sunset })
29 }
30
31 /// Runs the session to completion.
32 ///
33 /// `rsock` and `wsock` are the SSH network channel (TCP port 22 or equivalent).
34 /// `b` is an instance of [`ServBehaviour`] which defines application behaviour.
35 pub async fn run<S: ServBehaviour>(&self,
36 rsock: &mut impl Read,
37 wsock: &mut impl Write,
38 b: &SunsetMutex<S>) -> Result<()>
39 {
40 self.sunset.run(rsock, wsock, b).await
41 }
42
43 /// Returns a [`ChanInOut`] representing a channel.
44 ///
45 /// For a shell this is stdin/stdout, for other channel types it is the only
46 /// data type.
47 /// `ch` is the [`ChanHandle`] passed to the application's `Behaviour`
48 /// methods.
49 pub async fn stdio(&'a self, ch: ChanHandle) -> Result<ChanInOut<'a>> {
50 let num = ch.num();
51 self.sunset.add_channel(ch, 1).await?;
52 Ok(ChanInOut::new(num, ChanData::Normal, &self.sunset))
53 }
54
55 /// Retrieve the stdin/stdout/stderr streams.
56 ///
57 /// If stderr is not required, use [`stdio()`][Self::stdio] instead to avoid needing to poll
58 /// the returned stderr.
59 /// The session will block until the streams are drained (they use the session buffer),
60 /// so they must be drained if used.
61 pub async fn stdio_stderr(&'a self, ch: ChanHandle)
62 -> Result<(ChanInOut<'a>, ChanOut<'a>)> {
63 let num = ch.num();
64 self.sunset.add_channel(ch, 2).await?;
65 let i = ChanInOut::new(num, ChanData::Normal, &self.sunset);
66 let e = ChanOut::new(num, ChanData::Stderr, &self.sunset);
67 Ok((i, e))
68 }
69
70 // TODO: add stdio_stderr()
71}