use async_trait::async_trait; use smol::{ io::{split, AsyncReadExt, AsyncWriteExt, ReadHalf, WriteHalf}, lock::Mutex, net::{TcpListener, TcpStream}, }; use crate::{ connection::{Connection, ToConn}, endpoint::{Addr, Endpoint, Port}, listener::{ConnListener, ToListener}, Error, Result, }; /// TCP network connection implementation of the [`Connection`] trait. pub struct TcpConn { inner: TcpStream, read: Mutex>, write: Mutex>, } impl TcpConn { /// Creates a new TcpConn pub fn new(conn: TcpStream) -> Self { let (read, write) = split(conn.clone()); Self { inner: conn, read: Mutex::new(read), write: Mutex::new(write), } } } #[async_trait] impl Connection for TcpConn { fn peer_endpoint(&self) -> Result { Ok(Endpoint::new_tcp_addr(&self.inner.peer_addr()?)) } fn local_endpoint(&self) -> Result { Ok(Endpoint::new_tcp_addr(&self.inner.local_addr()?)) } async fn read(&self, buf: &mut [u8]) -> Result { self.read.lock().await.read(buf).await.map_err(Error::from) } async fn write(&self, buf: &[u8]) -> Result { self.write .lock() .await .write(buf) .await .map_err(Error::from) } } #[async_trait] impl ConnListener for TcpListener { fn local_endpoint(&self) -> Result { Ok(Endpoint::new_tcp_addr(&self.local_addr()?)) } async fn accept(&self) -> Result> { let (conn, _) = self.accept().await?; conn.set_nodelay(true)?; Ok(Box::new(TcpConn::new(conn))) } } /// Connects to the given TCP address and port. pub async fn dial_tcp(addr: &Addr, port: &Port) -> Result { let address = format!("{}:{}", addr, port); let conn = TcpStream::connect(address).await?; conn.set_nodelay(true)?; Ok(TcpConn::new(conn)) } /// Listens on the given TCP address and port. pub async fn listen_tcp(addr: &Addr, port: &Port) -> Result { let address = format!("{}:{}", addr, port); let listener = TcpListener::bind(address).await?; Ok(listener) } impl From for Box { fn from(conn: TcpStream) -> Self { Box::new(TcpConn::new(conn)) } } impl From for Box { fn from(listener: TcpListener) -> Self { Box::new(listener) } } impl ToConn for TcpStream { fn to_conn(self) -> Box { self.into() } } impl ToConn for TcpConn { fn to_conn(self) -> Box { Box::new(self) } } impl ToListener for TcpListener { fn to_listener(self) -> Box { self.into() } }