flnet/web_rtc/messages.rs
1//! # Messages for WebRTC connections
2//!
3//! This is a list of messages that are used by the [`crate::web_rtc::WebRTCConn`] and
4//! [`crate::web_rtc::node_connection::NodeConnection`] brokers to communicate with the libc and wasm implementations
5//! of the WebRTC subsystem.
6//! Both the wasm and the libc implementation for the WebRTC system return a [`Broker<WebRTCMessage>`]
7//! that is then given to the [`crate::web_rtc::WebRTCConn`].
8use futures::{channel::oneshot::Canceled, Future};
9use serde::{Deserialize, Serialize};
10use std::sync::mpsc::RecvError;
11use thiserror::Error;
12
13use flmodules::{broker::Broker, nodeids::NodeID};
14
15use super::node_connection::Direction;
16
17#[derive(Debug, Error)]
18/// Error messages for failing setups
19pub enum SetupError {
20 /// WebRTC setup fail
21 #[error("Couldn't setup: {0}")]
22 SetupFail(String),
23 /// Didn't receive an appropriate state from the signalling server / the remote node
24 #[error("Invalid state: {0}")]
25 InvalidState(String),
26 /// Couldn't send over the network
27 #[error("While sending: {0}")]
28 Send(String),
29 /// Some error from the broker subsystem
30 #[error(transparent)]
31 Broker(#[from] flmodules::broker::BrokerError),
32 /// Couldn't receive a message
33 #[error(transparent)]
34 Recv(#[from] RecvError),
35 /// Got cancelled
36 #[error(transparent)]
37 Canceled(#[from] Canceled),
38}
39
40#[derive(Debug, Clone, PartialEq)]
41/// Messages used in the WebRTC subsystem.
42pub enum WebRTCMessage {
43 /// Sent from the WebRTC subsystem
44 Output(WebRTCOutput),
45 /// Commands for the WebRTC subsystem
46 Input(WebRTCInput),
47}
48
49#[derive(Debug, Clone, PartialEq)]
50/// Output messages for the WebRTC subsystem
51pub enum WebRTCOutput {
52 /// Successfully connected to a node
53 Connected,
54 /// Successfully disconnected to a node
55 Disconnected,
56 /// Received a message from a node
57 Text(String),
58 /// Setup message for setting up or maintaining a WebRTC connection
59 Setup(PeerMessage),
60 /// Current state of the connection
61 State(ConnectionStateMap),
62 /// Generic error
63 Error(String),
64}
65
66#[derive(Debug, Clone, PartialEq)]
67/// Command for the WebRTC subsystem
68pub enum WebRTCInput {
69 /// Send a text message
70 Text(String),
71 /// Treat a setup message
72 Setup(PeerMessage),
73 /// Flush all pending messages
74 Flush,
75 /// Send the current state of the connection
76 UpdateState,
77 /// Try to reconnect, or throw an error if incoming connection
78 Reset,
79}
80
81#[cfg(not(feature = "nosend"))]
82/// The spawner will create a new [`Broker<WebRTCMessage>`] ready to handle either an incoing
83/// or an outgoing connection.
84pub type WebRTCSpawner = Box<
85 dyn Fn() -> Box<dyn Future<Output = Result<Broker<WebRTCMessage>, SetupError>> + Unpin + Send>
86 + Send
87 + Sync,
88>;
89#[cfg(feature = "nosend")]
90/// The spawner will create a new [`Broker<WebRTCMessage>`] ready to handle either an incoing
91/// or an outgoing connection.
92pub type WebRTCSpawner =
93 Box<dyn Fn() -> Box<dyn Future<Output = Result<Broker<WebRTCMessage>, SetupError>> + Unpin>>;
94
95#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
96/// How the current connection is being setup.
97pub enum ConnType {
98 /// No usable state from the subsystem
99 Unknown,
100 /// Direct connection to the host
101 Host,
102 /// Got connection details from a STUN server
103 STUNPeer,
104 /// Got connection details from a STUN server
105 STUNServer,
106 /// Connection going through a TURN server, so no direct node-to-node connection
107 TURN,
108}
109
110#[derive(PartialEq, Debug, Clone, Copy, Serialize, Deserialize)]
111/// In what signalling state the WebRTC subsystem is
112pub enum SignalingState {
113 /// Currently closed, no setup going on
114 Closed,
115 /// Setup started, but connection is not usable
116 Setup,
117 /// Connection is stable and can be used
118 Stable,
119}
120
121/// This is copied from the web-sys RtcIceGatheringState - not sure that this is
122/// also available in the libc-implementation.
123#[derive(PartialEq, Debug, Clone, Copy)]
124pub enum IceGatheringState {
125 /// Just started the connection
126 New,
127 /// Gathering first information
128 Gathering,
129 /// Enough information for connection setup
130 Complete,
131}
132
133/// This is copied from the web-sys RtcIceConnectionState - not sure that this is
134/// also available in the libc-implementation.
135#[derive(PartialEq, Debug, Clone, Copy)]
136pub enum IceConnectionState {
137 New,
138 Checking,
139 Connected,
140 Completed,
141 Failed,
142 Disconnected,
143 Closed,
144}
145
146/// This is copied from the web-sys RtcDataChannelState - not sure that this is
147/// also available in the libc-implementation.
148#[derive(PartialEq, Debug, Clone, Copy)]
149pub enum DataChannelState {
150 Connecting,
151 Open,
152 Closing,
153 Closed,
154}
155
156/// Some statistics about the connection
157#[derive(PartialEq, Debug, Clone, Copy)]
158pub struct ConnectionStateMap {
159 pub type_local: ConnType,
160 pub type_remote: ConnType,
161 pub signaling: SignalingState,
162 pub ice_gathering: IceGatheringState,
163 pub ice_connection: IceConnectionState,
164 pub data_connection: Option<DataChannelState>,
165 pub rx_bytes: u64,
166 pub tx_bytes: u64,
167 pub delay_ms: u32,
168}
169
170impl Default for ConnectionStateMap {
171 fn default() -> Self {
172 Self {
173 type_local: ConnType::Unknown,
174 type_remote: ConnType::Unknown,
175 signaling: SignalingState::Closed,
176 ice_gathering: IceGatheringState::New,
177 ice_connection: IceConnectionState::New,
178 data_connection: None,
179 rx_bytes: 0,
180 tx_bytes: 0,
181 delay_ms: 0,
182 }
183 }
184}
185
186/// A setup message being sent between two nodes to setup or maintain
187/// a WebRTC connection.
188#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
189pub enum PeerMessage {
190 /// The receiver should start the connection by creating an offer
191 Init,
192 /// The receiver should use the given information to create an answer
193 Offer(String),
194 /// The receiver should use the given information and wait for enough [`PeerMessage::IceCandidate`]s to
195 /// finalize the setup of the connection
196 Answer(String),
197 /// Detailed information about available ports, poked holes in the NAT, or any other information
198 /// to connect two nodes over WebRTC
199 IceCandidate(String),
200}
201
202impl std::fmt::Display for PeerMessage {
203 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
204 match self {
205 PeerMessage::Init => write!(f, "Init"),
206 PeerMessage::Offer(_) => write!(f, "Offer"),
207 PeerMessage::Answer(_) => write!(f, "Answer"),
208 PeerMessage::IceCandidate(_) => write!(f, "IceCandidate"),
209 }
210 }
211}
212
213/// Data sent between two nodes using the signalling server to set up
214/// a peer-to-peer connection over WebRTC.
215#[derive(Debug, Deserialize, Serialize, Clone, PartialEq)]
216pub struct PeerInfo {
217 /// The ID of the node sending the [`PeerMessage::Init`] message: the
218 /// creator of the outgoing connection
219 pub id_init: NodeID,
220 /// The ID of the node receiving the [`PeerMessage::Init`] message: the
221 /// creator of the incoming connection
222 pub id_follow: NodeID,
223 /// The actual data to be sent to the WebRTC subsystem
224 pub message: PeerMessage,
225}
226
227impl std::fmt::Display for PeerInfo {
228 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
229 write!(
230 f,
231 "init: {} - follow: {} - msg: {}",
232 self.id_init, self.id_follow, self.message
233 )
234 }
235}
236
237impl PeerInfo {
238 /// Creates a new [`PeerInfo`] with an init message
239 pub fn new(init: &NodeID, follow: &NodeID) -> PeerInfo {
240 PeerInfo {
241 id_init: *init,
242 id_follow: *follow,
243 message: PeerMessage::Init,
244 }
245 }
246
247 /// Gets the other ID given one of the two IDs
248 pub fn get_remote(&self, local: &NodeID) -> Option<NodeID> {
249 if self.id_init == *local {
250 return Some(self.id_follow);
251 }
252 if self.id_follow == *local {
253 return Some(self.id_init);
254 }
255 None
256 }
257
258 /// Gets the direction of the setup given the local ID
259 pub fn get_direction(&self, local: &NodeID) -> Direction {
260 if self.id_init == *local {
261 return Direction::Outgoing;
262 }
263 return Direction::Incoming;
264 }
265}