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}