rustp2p_transport/
lib.rs

1mod task;
2
3pub use rustp2p;
4use rustp2p::config::LoadBalance;
5use rustp2p::pipe::PeerNodeAddress;
6use rustp2p::protocol::node_id::GroupCode;
7use std::io;
8use std::net::Ipv4Addr;
9pub use tcp_ip;
10/// A builder for configuring and creating a `Transport` instance.
11/// Supports setting IP, port, peers, and group code for network isolation.
12#[derive(Clone, Debug, Default)]
13pub struct TransportBuilder {
14    group_code: Option<String>,
15    endpoint: Option<Ipv4Addr>,
16    load_balance: Option<LoadBalance>,
17    listen_port: Option<u16>,
18    peers: Option<Vec<PeerNodeAddress>>,
19}
20impl TransportBuilder {
21    /// Sets the group code for network isolation.
22    pub fn group_code(mut self, group_code: String) -> Self {
23        self.group_code = Some(group_code);
24        self
25    }
26    /// Sets the IP address of the node (must be set).
27    pub fn endpoint(mut self, endpoint: Ipv4Addr) -> Self {
28        self.endpoint = Some(endpoint);
29        self
30    }
31    /// Sets the port for the node to listen on (optional).
32    pub fn listen_port(mut self, listen_port: u16) -> Self {
33        self.listen_port = Some(listen_port);
34        self
35    }
36    /// Sets the list of directly connected peer nodes (optional).
37    pub fn peers(mut self, peers: Vec<PeerNodeAddress>) -> Self {
38        self.peers = Some(peers);
39        self
40    }
41    pub fn load_balance(mut self, load_balance: LoadBalance) -> Self {
42        self.load_balance = Some(load_balance);
43        self
44    }
45    fn config(self) -> io::Result<(rustp2p::config::PipeConfig, tcp_ip::IpStackConfig)> {
46        let Some(ip) = self.endpoint else {
47            return Err(io::Error::new(io::ErrorKind::Other, "IP must be set"));
48        };
49        let mut udp_config = rustp2p::config::UdpPipeConfig::default();
50        let mut tcp_config = rustp2p::config::TcpPipeConfig::default();
51        if let Some(port) = self.listen_port {
52            udp_config = udp_config.set_simple_udp_port(port);
53            tcp_config = tcp_config.set_tcp_port(port);
54        }
55        let mut p2p_config = rustp2p::config::PipeConfig::empty()
56            .set_load_balance(self.load_balance.unwrap_or(LoadBalance::RoundRobin))
57            .set_udp_pipe_config(udp_config)
58            .set_tcp_pipe_config(tcp_config)
59            .set_node_id(ip.into());
60        if let Some(peers) = self.peers {
61            p2p_config = p2p_config.set_direct_addrs(peers);
62        }
63        if let Some(group_code) = self.group_code {
64            p2p_config = p2p_config.set_group_code(string_to_group_code(&group_code))
65        }
66
67        let ip_stack_config = tcp_ip::IpStackConfig::default();
68        Ok((p2p_config, ip_stack_config))
69    }
70    #[cfg(feature = "global")]
71    pub async fn build_context(self) -> io::Result<()> {
72        let (p2p_config, ip_stack_config) = self.config()?;
73        transport_from_config(p2p_config, ip_stack_config).await
74    }
75    #[cfg(not(feature = "global"))]
76    pub async fn build(self) -> io::Result<tcp_ip::IpStack> {
77        let (p2p_config, ip_stack_config) = self.config()?;
78        transport_from_config(p2p_config, ip_stack_config).await
79    }
80}
81/// Build through complete config
82#[cfg(feature = "global")]
83pub async fn transport_from_config(
84    rustp2p_config: rustp2p::config::PipeConfig,
85    tcp_ip_config: tcp_ip::IpStackConfig,
86) -> io::Result<()> {
87    transport_from_config0(rustp2p_config, tcp_ip_config)
88        .await
89        .map(|_| ())
90}
91/// Build through complete config
92#[cfg(not(feature = "global"))]
93pub async fn transport_from_config(
94    rustp2p_config: rustp2p::config::PipeConfig,
95    tcp_ip_config: tcp_ip::IpStackConfig,
96) -> io::Result<tcp_ip::IpStack> {
97    transport_from_config0(rustp2p_config, tcp_ip_config).await
98}
99async fn transport_from_config0(
100    rustp2p_config: rustp2p::config::PipeConfig,
101    tcp_ip_config: tcp_ip::IpStackConfig,
102) -> io::Result<tcp_ip::IpStack> {
103    let mtu = tcp_ip_config.mtu;
104    let pipe = rustp2p::pipe::Pipe::new(rustp2p_config).await?;
105    let Some(node_id) = pipe.writer().pipe_context().load_id() else {
106        return Err(io::Error::new(io::ErrorKind::Other, "Node ID must be set"));
107    };
108    #[cfg(not(feature = "global"))]
109    let (ip_stack, ip_stack_send, ip_stack_recv) = tcp_ip::ip_stack(tcp_ip_config)?;
110    #[cfg(feature = "global")]
111    let (ip_stack_send, ip_stack_recv) = tcp_ip::ip_stack(tcp_ip_config)?;
112    #[cfg(feature = "global")]
113    let ip_stack = tcp_ip::IpStack::get()?;
114    ip_stack.routes().set_default_v4(node_id.into());
115    let mut v6: [u8; 16] = [
116        0xfd, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xab, 0xcd, 0xef, 0x12, 0x34, 0x56, 0, 0, 0, 0,
117    ];
118    v6[12..].copy_from_slice(node_id.as_ref());
119    ip_stack
120        .routes()
121        .set_default_v6(std::net::Ipv6Addr::from(v6));
122    task::start(mtu, pipe, ip_stack_send, ip_stack_recv).await?;
123    Ok(ip_stack)
124}
125fn string_to_group_code(input: &str) -> GroupCode {
126    let mut array = [0u8; 16];
127    let bytes = input.as_bytes();
128    let len = bytes.len().min(16);
129    array[..len].copy_from_slice(&bytes[..len]);
130    array.into()
131}