moonpool_core/
network.rs

1//! Network provider abstraction for simulation and real networking.
2//!
3//! This module provides trait-based networking that allows seamless swapping
4//! between real Tokio networking and simulated networking for testing.
5
6use async_trait::async_trait;
7use std::io;
8use tokio::io::{AsyncRead, AsyncWrite};
9
10/// Provider trait for creating network connections and listeners.
11///
12/// Single-core design - no Send bounds needed.
13/// Clone allows sharing providers across multiple peers efficiently.
14#[async_trait(?Send)]
15pub trait NetworkProvider: Clone {
16    /// The TCP stream type for this provider.
17    type TcpStream: AsyncRead + AsyncWrite + Unpin + 'static;
18    /// The TCP listener type for this provider.
19    type TcpListener: TcpListenerTrait<TcpStream = Self::TcpStream> + 'static;
20
21    /// Create a TCP listener bound to the given address.
22    async fn bind(&self, addr: &str) -> io::Result<Self::TcpListener>;
23
24    /// Connect to a remote address.
25    async fn connect(&self, addr: &str) -> io::Result<Self::TcpStream>;
26}
27
28/// Trait for TCP listeners that can accept connections.
29#[async_trait(?Send)]
30pub trait TcpListenerTrait {
31    /// The TCP stream type that this listener produces.
32    type TcpStream: AsyncRead + AsyncWrite + Unpin + 'static;
33
34    /// Accept a single incoming connection.
35    async fn accept(&self) -> io::Result<(Self::TcpStream, String)>;
36
37    /// Get the local address this listener is bound to.
38    fn local_addr(&self) -> io::Result<String>;
39}
40
41/// Real Tokio networking implementation.
42#[derive(Debug, Clone)]
43pub struct TokioNetworkProvider;
44
45impl TokioNetworkProvider {
46    /// Create a new Tokio network provider.
47    pub fn new() -> Self {
48        Self
49    }
50}
51
52impl Default for TokioNetworkProvider {
53    fn default() -> Self {
54        Self::new()
55    }
56}
57
58#[async_trait(?Send)]
59impl NetworkProvider for TokioNetworkProvider {
60    type TcpStream = tokio::net::TcpStream;
61    type TcpListener = TokioTcpListener;
62
63    async fn bind(&self, addr: &str) -> io::Result<Self::TcpListener> {
64        let listener = tokio::net::TcpListener::bind(addr).await?;
65        Ok(TokioTcpListener { inner: listener })
66    }
67
68    async fn connect(&self, addr: &str) -> io::Result<Self::TcpStream> {
69        tokio::net::TcpStream::connect(addr).await
70    }
71}
72
73/// Wrapper for Tokio TcpListener to implement our trait.
74#[derive(Debug)]
75pub struct TokioTcpListener {
76    inner: tokio::net::TcpListener,
77}
78
79#[async_trait(?Send)]
80impl TcpListenerTrait for TokioTcpListener {
81    type TcpStream = tokio::net::TcpStream;
82
83    async fn accept(&self) -> io::Result<(Self::TcpStream, String)> {
84        let (stream, addr) = self.inner.accept().await?;
85        Ok((stream, addr.to_string()))
86    }
87
88    fn local_addr(&self) -> io::Result<String> {
89        Ok(self.inner.local_addr()?.to_string())
90    }
91}