sunset_embassy/
client.rs

1use embedded_io_async::{Read, Write};
2
3use sunset::*;
4
5use crate::*;
6use sunset::ChanData;
7use embassy_sunset::EmbassySunset;
8use embassy_channel::{ChanInOut, ChanIn};
9
10/// An async SSH client instance 
11///
12/// The [`run()`][Self::run] method runs the session to completion, with application behaviour
13/// defined by the [`CliBehaviour`] instance.
14///
15/// Once authentication has completed ([`authenticated()`][CliBehaviour] is called), the application
16/// may open remote channels with [`open_session_pty()`][Self::open_session_pty] etc.
17///
18/// This is async executor agnostic, though requires the `CliBehaviour` instance
19/// to be wrapped in a [`SunsetMutex`].
20pub struct SSHClient<'a> {
21    sunset: EmbassySunset<'a>,
22}
23
24impl<'a> SSHClient<'a> {
25    pub fn new(inbuf: &'a mut [u8], outbuf: &'a mut [u8],
26        ) -> Result<Self> {
27        let runner = Runner::new_client(inbuf, outbuf)?;
28        let sunset = EmbassySunset::new(runner);
29        Ok(Self { sunset })
30    }
31
32    /// Runs the session to completion.
33    ///
34    /// `rsock` and `wsock` are the SSH network channel (TCP port 22 or equivalent).
35    /// `b` is an instance of [`CliBehaviour`] which defines application behaviour.
36    pub async fn run<C: CliBehaviour>(&self,
37        rsock: &mut impl Read,
38        wsock: &mut impl Write,
39        b: &SunsetMutex<C>) -> Result<()>
40    {
41        self.sunset.run(rsock, wsock, b).await
42    }
43
44    pub async fn exit(&self) {
45        self.sunset.exit().await
46    }
47
48    pub async fn open_session_nopty(&'a self)
49    -> Result<(ChanInOut<'a>, ChanIn<'a>)> {
50        let chan = self.sunset.with_runner(|runner| {
51            runner.open_client_session()
52        }).await?;
53
54        let num = chan.num();
55        self.sunset.add_channel(chan, 2).await?;
56
57        let cstd = ChanInOut::new(num, ChanData::Normal, &self.sunset);
58        let cerr = ChanIn::new(num, ChanData::Stderr, &self.sunset);
59        Ok((cstd, cerr))
60    }
61
62    pub async fn open_session_pty(&'a self) -> Result<ChanInOut<'a>> {
63        let chan = self.sunset.with_runner(|runner| {
64            runner.open_client_session()
65        }).await?;
66
67        let num = chan.num();
68        self.sunset.add_channel(chan, 1).await?;
69        let cstd = ChanInOut::new(num, ChanData::Normal, &self.sunset);
70        Ok(cstd)
71    }
72}