It works by using an ugly method, entering the tokio runtime manually to be able to await on the Handle::data() function from a non-async method.
So from the server example in tokio source, I add the following code at src/lib.rs#111:
futures::executor::block_on(s.data(*chan, CryptoVec::from_slice(data))).expect("error blocking on s.data()");
I imagine refactoring of the Server Handler trait to have asyncronous functions would be needed to accomplish this in a clean way ? I don’t realize how much work it represents.
After changing increasing the timeouts to 30s and adding a little printf debugging:
fn data(self, channel: ChannelId, data: &[u8], mut session: Session) -> Self::FutureUnit {
println!("rx data: {:?}", data);
I can now see what I type being received on the server, after 10 or 20 seconds.
I found a more-reliable-but-still-disgusting way to send messages to a thrussh server session from outside the async loop, see bellow.
Note that a single send should be done at a time, as a new task will be spawned every time messages would likely arrive out-of-order.
asyncsim_send(&server_handle, channel, b"hey you", false);
fn asyncsim_send(handle: &thrussh::server::Handle, channel: thrussh::ChannelId, bytes: &[u8], mut close_after_send: bool) {
let tokiohandle = tokio::runtime::Handle::current();
let mut sess = handle.clone();
let buf = bytes.to_owned();
tokiohandle.spawn(async move {
match sess.data(channel, thrussh::CryptoVec::from_slice(&buf)).await {
Ok(_) => (),
Err(_) => {
debug!("detected error while send, closing connection");
close_after_send = true;
},
}
if close_after_send {
match sess.close(channel).await {
Ok(_) => (),
Err(_) => warn!("detected error while close"),
}
}
});
}
Here is what I changed line 111 to.
let r =
futures::executor::block_on(s.data(*channel, CryptoVec::from_slice(data)));
if let Err(_) = r {
return futures::future::ready(Err(anyhow!(
"Error sending data to client {}",
*id
)));
}
It would be nice to switch the trait to use async_trait as that would make the traits MUCH easier to write using async/await style code.
Sorry to gravedig but yes, please use async fn
in traits now that it’s stabilized. Having to name every single future as a trait type makes certain things very hard to code for. Especially since the server example doesn’t work as one would expect.
I’m using the example server in src/lib.rs, that is supposed to send input data from a client to all other clients using
server::session::Handle::data()
, but i can’t make it work. I’m using 2 ssh clients, that do authenticate successfully with password authentication, but data sent from client 1 does not end up in client 2. Using debug prints i can see the data() function in theserver::Handler
is getting called when sending data from client 1, and i see in client 1 the data being sent back to itself.For both clients i use:
Any idea why the forwarding does not work ? Isn’t what is typed on client 1 supposed to be forwarded to client 2 output, based on the code at src/lib.rs#111
s.data(*channel, CryptoVec::from_slice(data));
?In order to understand deeper what is happening, I’m trying to follow the server example comments “It doesn’t handle errors when
s.data
returns an error”. But, I can’t seem to find a way to detect and print these potential errors on Future properly, anyone willing to help me here with a little example code ?Sorry for the noobish questions i’m very new to rust ! Thanks for your work on thrussh, it is actually this library that is the starting point of my interest in this language.