use std::sync::Arc;
use crate::network::{NetworkProvider, PeerAddr};
use super::{resolve_dial_addr, RawIncoming, RawListener, RawTransport, TransportError};
pub struct TcpTransport<N: NetworkProvider> {
network: Arc<N>,
}
impl<N: NetworkProvider + 'static> TcpTransport<N> {
pub fn new(network: Arc<N>) -> Self {
Self { network }
}
}
impl<N: NetworkProvider + 'static> RawTransport for TcpTransport<N> {
async fn open(
&self,
addr: &PeerAddr,
port: u16,
) -> Result<tokio::net::TcpStream, TransportError> {
let dial_addr = resolve_dial_addr(addr);
tracing::debug!(addr = %dial_addr, port, "tcp: dialing peer");
let stream = self
.network
.dial_tcp(&dial_addr, port)
.await
.map_err(|e| TransportError::ConnectFailed(format!("tcp dial: {e}")))?;
tracing::debug!(addr = %dial_addr, port, "tcp: connected");
Ok(stream)
}
async fn listen(&self, port: u16) -> Result<RawListener, TransportError> {
tracing::debug!(port, "tcp: starting listener");
let mut tcp_listener = self
.network
.listen_tcp(port)
.await
.map_err(|e| TransportError::ListenFailed(format!("tcp listen: {e}")))?;
let actual_port = tcp_listener.port;
let (tx, rx) = tokio::sync::mpsc::channel::<RawIncoming>(64);
tokio::spawn(async move {
loop {
match tcp_listener.incoming.recv().await {
Some(incoming) => {
let raw = RawIncoming {
stream: incoming.stream,
remote_addr: incoming.remote_addr,
};
if tx.send(raw).await.is_err() {
tracing::debug!("tcp: listener channel closed");
break;
}
}
None => {
tracing::debug!("tcp: network listener channel closed");
break;
}
}
}
});
Ok(RawListener::new(rx, actual_port))
}
}