pub mod known_hosts;
pub mod ssh;
#[cfg(feature = "tls")]
pub mod tls;
use crate::error::TransportError;
use async_trait::async_trait;
#[async_trait]
pub trait Transport: Send + Sync {
async fn write_all(&mut self, data: &[u8]) -> Result<(), TransportError>;
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, TransportError>;
async fn close(&mut self) -> Result<(), TransportError>;
}
#[cfg(test)]
pub mod mock {
use super::*;
pub struct MockTransport {
read_data: Vec<u8>,
read_pos: usize,
pub written: Vec<u8>,
pub closed: bool,
}
impl MockTransport {
pub fn new(read_data: Vec<u8>) -> Self {
Self {
read_data,
read_pos: 0,
written: Vec::new(),
closed: false,
}
}
}
#[async_trait]
impl Transport for MockTransport {
async fn write_all(&mut self, data: &[u8]) -> Result<(), TransportError> {
if self.closed {
return Err(TransportError::Io(std::io::Error::new(
std::io::ErrorKind::BrokenPipe,
"transport closed",
)));
}
self.written.extend_from_slice(data);
Ok(())
}
async fn read(&mut self, buf: &mut [u8]) -> Result<usize, TransportError> {
if self.closed {
return Err(TransportError::Io(std::io::Error::new(
std::io::ErrorKind::BrokenPipe,
"transport closed",
)));
}
let remaining = &self.read_data[self.read_pos..];
if remaining.is_empty() {
return Ok(0);
}
let to_read = std::cmp::min(buf.len(), remaining.len());
buf[..to_read].copy_from_slice(&remaining[..to_read]);
self.read_pos += to_read;
Ok(to_read)
}
async fn close(&mut self) -> Result<(), TransportError> {
self.closed = true;
Ok(())
}
}
}