use russh::client::Msg;
use russh::{Channel, ChannelMsg};
use tokio::io::{AsyncReadExt, AsyncWriteExt, DuplexStream};
use tracing::{debug, trace};
pub fn channel_to_stream(mut channel: Channel<Msg>) -> DuplexStream {
let (app_side, bridge_side) = tokio::io::duplex(64 * 1024);
let (mut bridge_read, mut bridge_write) = tokio::io::split(bridge_side);
tokio::spawn(async move {
let mut local_buf = [0u8; 8192];
loop {
tokio::select! {
biased;
msg = channel.wait() => {
match msg {
Some(ChannelMsg::Data { data }) => {
trace!("SSH channel -> stream: {} bytes", data.len());
if bridge_write.write_all(&data).await.is_err() {
break;
}
let _ = bridge_write.flush().await;
}
Some(ChannelMsg::Eof) | None => {
debug!("SSH channel closed");
let _ = bridge_write.shutdown().await;
break;
}
_ => {} }
}
result = bridge_read.read(&mut local_buf) => {
match result {
Ok(0) => {
debug!("Stream closed by app");
let _ = channel.eof().await;
break;
}
Ok(n) => {
trace!("Stream -> SSH channel: {} bytes", n);
if channel.data(&local_buf[..n]).await.is_err() {
break;
}
}
Err(_) => break,
}
}
}
}
let _ = channel.eof().await;
debug!("Channel stream bridge ended");
});
app_side
}