use std::io::{Read, Write};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TransportMode {
Client,
Server,
}
pub trait Transport: Read + Write + Send {
fn name(&self) -> &str;
fn is_encrypted(&self) -> bool;
fn peer_identity(&self) -> Option<String>;
}
pub struct PlaintextTransport {
inner: std::net::TcpStream,
peer: Option<String>,
}
impl PlaintextTransport {
pub fn new(stream: std::net::TcpStream) -> Self {
let peer = stream.peer_addr().ok().map(|a| a.to_string());
Self {
inner: stream,
peer,
}
}
}
impl Read for PlaintextTransport {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.inner.read(buf)
}
}
impl Write for PlaintextTransport {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.inner.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.inner.flush()
}
}
impl Transport for PlaintextTransport {
fn name(&self) -> &str {
"plaintext"
}
fn is_encrypted(&self) -> bool {
false
}
fn peer_identity(&self) -> Option<String> {
self.peer.clone()
}
}
pub trait TransportFactory: Send + Sync {
fn wrap(&self, stream: std::net::TcpStream, mode: TransportMode) -> Box<dyn Transport>;
fn name(&self) -> &str;
}
pub struct PlaintextTransportFactory;
impl TransportFactory for PlaintextTransportFactory {
fn wrap(&self, stream: std::net::TcpStream, _mode: TransportMode) -> Box<dyn Transport> {
Box::new(PlaintextTransport::new(stream))
}
fn name(&self) -> &str {
"plaintext"
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn plaintext_not_encrypted() {
let factory = PlaintextTransportFactory;
assert_eq!(factory.name(), "plaintext");
}
#[test]
fn transport_mode_eq() {
assert_eq!(TransportMode::Client, TransportMode::Client);
assert_ne!(TransportMode::Client, TransportMode::Server);
}
#[test]
fn factory_implements_trait() {
let factory: Box<dyn TransportFactory> = Box::new(PlaintextTransportFactory);
assert_eq!(factory.name(), "plaintext");
}
}