use std::{future::Future, time::Duration}; use actix_web::web::Bytes; use russh::{ChannelId, server::Handle}; use tokio::{ io::{AsyncRead, AsyncReadExt}, time::sleep, }; pub async fn forward<'a, R, Fut, Fwd>( session_handle: &'a Handle, chan_id: ChannelId, r: &mut R, mut fwd: Fwd, ) -> Result<(), russh::Error> where R: AsyncRead + Send + Unpin, Fut: Future> + 'a, Fwd: FnMut(&'a Handle, ChannelId, Bytes) -> Fut, { const BUF_SIZE: usize = 1024 * 32; const MAX_RETRIES: usize = 5; const RETRY_DELAY: u64 = 10; let mut buf = [0u8; BUF_SIZE]; loop { let read = r.read(&mut buf).await.map_err(russh::Error::IO)?; if read == 0 { break; } let mut chunk = Bytes::copy_from_slice(&buf[..read]); let mut retries = 0; loop { match fwd(session_handle, chan_id, chunk).await { Ok(()) => break, Err(unsent) => { retries += 1; if retries >= MAX_RETRIES { return Ok(()); } chunk = unsent; sleep(Duration::from_millis(RETRY_DELAY)).await; } } } } Ok(()) }