1use std::sync::Arc;
2
3#[cfg(unix)]
4use std::os::unix::io::AsRawFd;
5#[cfg(windows)]
6use std::os::windows::io::{AsRawSocket, BorrowedSocket};
7
8use ssh2::{Agent, PublicKey, Session};
9
10use crate::{error::Error, session::get_session, session_stream::AsyncSessionStream};
11
12pub struct AsyncAgent<S> {
14 inner: Agent,
15 sess: Session,
16 stream: Arc<S>,
17}
18
19#[cfg(unix)]
20impl<S> AsyncAgent<S>
21where
22 S: AsRawFd + 'static,
23{
24 pub fn new(stream: S) -> Result<Self, Error> {
25 let mut session = get_session(None)?;
26 session.set_tcp_stream(stream.as_raw_fd());
27
28 let stream = Arc::new(stream);
29
30 let agent = session.agent()?;
31
32 Ok(Self {
33 inner: agent,
34 sess: session,
35 stream,
36 })
37 }
38}
39
40#[cfg(windows)]
41impl<S> AsyncAgent<S>
42where
43 S: AsRawSocket + 'static,
44{
45 pub fn new(stream: S) -> Result<Self, Error> {
46 let mut session = get_session(None)?;
47 session.set_tcp_stream(unsafe { BorrowedSocket::borrow_raw(stream.as_raw_socket()) });
48
49 let stream = Arc::new(stream);
50
51 let agent = session.agent()?;
52
53 Ok(Self {
54 inner: agent,
55 sess: session,
56 stream,
57 })
58 }
59}
60
61impl<S> AsyncAgent<S> {
62 pub(crate) fn from_parts(inner: Agent, sess: Session, stream: Arc<S>) -> Self {
63 Self {
64 inner,
65 sess,
66 stream,
67 }
68 }
69}
70
71impl<S> AsyncAgent<S> {
72 pub fn identities(&self) -> Result<Vec<PublicKey>, Error> {
73 self.inner.identities().map_err(Into::into)
74 }
75}
76
77impl<S> AsyncAgent<S>
78where
79 S: AsyncSessionStream + Send + Sync + 'static,
80{
81 pub async fn connect(&mut self) -> Result<(), Error> {
82 self.stream
83 .none_with(|| self.inner.connect(), &self.sess)
84 .await
85 }
86
87 pub async fn disconnect(&mut self) -> Result<(), Error> {
88 self.stream
89 .none_with(|| self.inner.disconnect(), &self.sess)
90 .await
91 }
92
93 pub async fn list_identities(&mut self) -> Result<(), Error> {
94 self.stream
95 .rw_with(|| self.inner.list_identities(), &self.sess)
96 .await
97 }
98
99 pub async fn userauth(&self, username: &str, identity: &PublicKey) -> Result<(), Error> {
100 self.stream
101 .rw_with(|| self.inner.userauth(username, identity), &self.sess)
102 .await
103 }
104}