message_io/network/
transport.rs

1use super::loader::{DriverLoader};
2
3#[cfg(feature = "tcp")]
4use crate::adapters::tcp::{TcpAdapter, TcpConnectConfig, TcpListenConfig};
5#[cfg(feature = "tcp")]
6use crate::adapters::framed_tcp::{FramedTcpAdapter, FramedTcpConnectConfig, FramedTcpListenConfig};
7#[cfg(feature = "udp")]
8use crate::adapters::udp::{self, UdpAdapter, UdpConnectConfig, UdpListenConfig};
9#[cfg(feature = "websocket")]
10use crate::adapters::ws::{self, WsAdapter};
11
12use serde::{Serialize, Deserialize};
13
14/// Enum to identified the underlying transport used.
15/// It can be passed to
16/// [`NetworkController::connect()`](crate::network::NetworkController::connect()) and
17/// [`NetworkController::listen()`](crate::network::NetworkController::connect()) methods
18/// to specify the transport used.
19#[derive(strum::EnumIter, Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Hash, Debug)]
20pub enum Transport {
21    /// TCP protocol (available through the *tcp* feature).
22    /// As stream protocol, receiving a message from TCP do not imply to read
23    /// the entire message.
24    /// If you want a packet based way to send over TCP, use `FramedTcp` instead.
25    #[cfg(feature = "tcp")]
26    Tcp,
27
28    /// Tcp framed protocol (available through the *tcp* feature).
29    /// Like TCP, but encoded with a slim frame layer to manage the data as a packet,
30    /// instead of as a stream.
31    /// It prefixes the message using variable integer encoding with the size of the message.
32    /// Most of the time you would want to use this instead of the raw `Tcp`.
33    #[cfg(feature = "tcp")]
34    FramedTcp,
35
36    /// UDP protocol (available through the *udp* feature).
37    /// Take into account that UDP is not connection oriented and a packet can be lost
38    /// or received disordered.
39    /// If it is specified in the listener and the address is a Ipv4 in the range of multicast ips
40    /// (from `224.0.0.0` to `239.255.255.255`), the listener will be configured in multicast mode.
41    #[cfg(feature = "udp")]
42    Udp,
43
44    /// WebSocket protocol (available through the *websocket* feature).
45    /// If you use a [`crate::network::RemoteAddr::Str`] in the `connect()` method,
46    /// you can specify an URL with `wss` of `ws` schemas to connect with or without security.
47    /// If you use a [`crate::network::RemoteAddr::Socket`] the socket will be a normal
48    /// websocket with the following uri: `ws://{SocketAddr}/message-io-default`.
49    #[cfg(feature = "websocket")]
50    Ws,
51}
52
53impl Transport {
54    /// Associates an adapter.
55    /// This method mounts the adapters to be used in the network instance.
56    pub fn mount_adapter(self, loader: &mut DriverLoader) {
57        match self {
58            #[cfg(feature = "tcp")]
59            Self::Tcp => loader.mount(self.id(), TcpAdapter),
60            #[cfg(feature = "tcp")]
61            Self::FramedTcp => loader.mount(self.id(), FramedTcpAdapter),
62            #[cfg(feature = "udp")]
63            Self::Udp => loader.mount(self.id(), UdpAdapter),
64            #[cfg(feature = "websocket")]
65            Self::Ws => loader.mount(self.id(), WsAdapter),
66        };
67    }
68
69    /// Maximum theorical packet payload length available for each transport.
70    ///
71    /// The value returned by this function is the **theorical maximum** and could not be valid for
72    /// all networks.
73    /// You can ensure your message not exceeds `udp::MAX_INTERNET_PAYLOAD_LEN` in order to be
74    /// more cross-platform compatible.
75    pub const fn max_message_size(self) -> usize {
76        match self {
77            #[cfg(feature = "tcp")]
78            Self::Tcp => usize::MAX,
79            #[cfg(feature = "tcp")]
80            Self::FramedTcp => usize::MAX,
81            #[cfg(feature = "udp")]
82            Self::Udp => udp::MAX_LOCAL_PAYLOAD_LEN,
83            #[cfg(feature = "websocket")]
84            Self::Ws => ws::MAX_PAYLOAD_LEN,
85        }
86    }
87
88    /// Tell if the transport protocol is a connection oriented protocol.
89    /// If it is, `Connection` and `Disconnection` events will be generated.
90    pub const fn is_connection_oriented(self) -> bool {
91        match self {
92            #[cfg(feature = "tcp")]
93            Transport::Tcp => true,
94            #[cfg(feature = "tcp")]
95            Transport::FramedTcp => true,
96            #[cfg(feature = "udp")]
97            Transport::Udp => false,
98            #[cfg(feature = "websocket")]
99            Transport::Ws => true,
100        }
101    }
102
103    /// Tell if the transport protocol is a packet-based protocol.
104    /// It implies that any send call corresponds to a data message event.
105    /// It satisfies that the number of bytes sent are the same as received.
106    /// The opossite of a packet-based is a stream-based transport (e.g Tcp).
107    /// In this case, reading a data message event do not imply reading the entire message sent.
108    /// It is in change of the user to determinate how to read the data.
109    pub const fn is_packet_based(self) -> bool {
110        match self {
111            #[cfg(feature = "tcp")]
112            Transport::Tcp => false,
113            #[cfg(feature = "tcp")]
114            Transport::FramedTcp => true,
115            #[cfg(feature = "udp")]
116            Transport::Udp => true,
117            #[cfg(feature = "websocket")]
118            Transport::Ws => true,
119        }
120    }
121
122    /// Returns the adapter id used for this transport.
123    /// It is equivalent to the position of the enum starting by 0
124    pub const fn id(self) -> u8 {
125        match self {
126            #[cfg(feature = "tcp")]
127            Transport::Tcp => 0,
128            #[cfg(feature = "tcp")]
129            Transport::FramedTcp => 1,
130            #[cfg(feature = "udp")]
131            Transport::Udp => 2,
132            #[cfg(feature = "websocket")]
133            Transport::Ws => 3,
134        }
135    }
136}
137
138impl From<u8> for Transport {
139    fn from(id: u8) -> Self {
140        match id {
141            #[cfg(feature = "tcp")]
142            0 => Transport::Tcp,
143            #[cfg(feature = "tcp")]
144            1 => Transport::FramedTcp,
145            #[cfg(feature = "udp")]
146            2 => Transport::Udp,
147            #[cfg(feature = "websocket")]
148            3 => Transport::Ws,
149            _ => panic!("Not available transport"),
150        }
151    }
152}
153
154impl std::fmt::Display for Transport {
155    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
156        write!(f, "{self:?}")
157    }
158}
159
160#[derive(Debug)]
161pub enum TransportConnect {
162    #[cfg(feature = "tcp")]
163    Tcp(TcpConnectConfig),
164    #[cfg(feature = "tcp")]
165    FramedTcp(FramedTcpConnectConfig),
166    #[cfg(feature = "udp")]
167    Udp(UdpConnectConfig),
168    #[cfg(feature = "websocket")]
169    Ws,
170}
171
172impl TransportConnect {
173    pub fn id(&self) -> u8 {
174        let transport = match self {
175            #[cfg(feature = "tcp")]
176            Self::Tcp(_) => Transport::Tcp,
177            #[cfg(feature = "tcp")]
178            Self::FramedTcp(_) => Transport::FramedTcp,
179            #[cfg(feature = "udp")]
180            Self::Udp(_) => Transport::Udp,
181            #[cfg(feature = "websocket")]
182            Self::Ws => Transport::Ws,
183        };
184
185        transport.id()
186    }
187}
188
189impl From<Transport> for TransportConnect {
190    fn from(transport: Transport) -> Self {
191        match transport {
192            #[cfg(feature = "tcp")]
193            Transport::Tcp => Self::Tcp(TcpConnectConfig::default()),
194            #[cfg(feature = "tcp")]
195            Transport::FramedTcp => Self::FramedTcp(FramedTcpConnectConfig::default()),
196            #[cfg(feature = "udp")]
197            Transport::Udp => Self::Udp(UdpConnectConfig::default()),
198            #[cfg(feature = "websocket")]
199            Transport::Ws => Self::Ws,
200        }
201    }
202}
203
204#[derive(Debug)]
205pub enum TransportListen {
206    #[cfg(feature = "tcp")]
207    Tcp(TcpListenConfig),
208    #[cfg(feature = "tcp")]
209    FramedTcp(FramedTcpListenConfig),
210    #[cfg(feature = "udp")]
211    Udp(UdpListenConfig),
212    #[cfg(feature = "websocket")]
213    Ws,
214}
215
216impl TransportListen {
217    pub fn id(&self) -> u8 {
218        let transport = match self {
219            #[cfg(feature = "tcp")]
220            Self::Tcp(_) => Transport::Tcp,
221            #[cfg(feature = "tcp")]
222            Self::FramedTcp(_) => Transport::FramedTcp,
223            #[cfg(feature = "udp")]
224            Self::Udp(_) => Transport::Udp,
225            #[cfg(feature = "websocket")]
226            Self::Ws => Transport::Ws,
227        };
228
229        transport.id()
230    }
231}
232
233impl From<Transport> for TransportListen {
234    fn from(transport: Transport) -> Self {
235        match transport {
236            #[cfg(feature = "tcp")]
237            Transport::Tcp => Self::Tcp(TcpListenConfig::default()),
238            #[cfg(feature = "tcp")]
239            Transport::FramedTcp => Self::FramedTcp(FramedTcpListenConfig::default()),
240            #[cfg(feature = "udp")]
241            Transport::Udp => Self::Udp(UdpListenConfig::default()),
242            #[cfg(feature = "websocket")]
243            Transport::Ws => Self::Ws,
244        }
245    }
246}