skyway_webrtc_gateway_api/peer/
formats.rs

1use std::fmt;
2
3use serde::de::{self, Visitor};
4use serde::{Deserialize, Deserializer, Serialize};
5
6use crate::data::DataConnectionIdWrapper;
7use crate::error;
8use crate::media::MediaConnectionIdWrapper;
9
10/// Identifier for PeerObject.
11///
12/// To avoid misuse, it is used with Token.
13#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
14pub struct PeerId(pub String);
15
16impl PeerId {
17    pub fn as_str(&self) -> &str {
18        self.0.as_str()
19    }
20
21    pub fn new(peer_id: impl Into<String>) -> Self {
22        PeerId(peer_id.into())
23    }
24}
25
26/// Token to avoid mesuse of Peer.
27///
28/// It is used with PeerId.
29#[derive(Serialize, Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
30pub struct Token(String);
31
32impl Token {
33    pub fn as_str(&self) -> &str {
34        self.0.as_str()
35    }
36
37    pub fn try_create(token: impl Into<String>) -> Result<Self, error::Error> {
38        // peer token's prefix is composed of a UUID and a prefix "pt-".
39        let token_string = token.into();
40        if !token_string.starts_with("pt-") {
41            return Err(error::Error::create_local_error(
42                "token str\'s prefix is \"pt-\"",
43            ));
44        }
45        if token_string.len() != 39 {
46            // It's length is 39(UUID: 36 + prefix: 3).
47            return Err(error::Error::create_local_error(
48                "token str's length should be 39",
49            ));
50        }
51        if !token_string.is_ascii() {
52            return Err(error::Error::create_local_error(
53                "token str should be ascii",
54            ));
55        }
56
57        Ok(Token(token_string))
58    }
59}
60
61#[test]
62fn create_token_success() {
63    let token = Token::try_create("pt-9749250e-d157-4f80-9ee2-359ce8524308").unwrap();
64    assert_eq!(token.as_str(), "pt-9749250e-d157-4f80-9ee2-359ce8524308");
65}
66
67#[test]
68fn create_token_not_start_with_pt() {
69    // peer token's prefix is "pt-"
70    let token = Token::try_create("vi-9749250e-d157-4f80-9ee2-359ce8524308");
71    if let Err(error::Error::LocalError(err)) = token {
72        assert_eq!(err.as_str(), "token str\'s prefix is \"pt-\"");
73    } else {
74        unreachable!();
75    }
76}
77
78#[test]
79fn create_token_not_sufficient_length() {
80    // this test is executed with 38 chars
81    let token = Token::try_create("pt-9749250e-d157-4f80-9ee2-359ce852430");
82    if let Err(error::Error::LocalError(err)) = token {
83        assert_eq!(err.as_str(), "token str\'s length should be 39");
84    } else {
85        unreachable!();
86    }
87}
88
89#[test]
90fn create_token_too_long() {
91    // this test is executed with 40 chars
92    let token = Token::try_create("pt-9749250e-d157-4f80-9ee2-359ce85243080");
93    if let Err(error::Error::LocalError(err)) = token {
94        assert_eq!(err.as_str(), "token str\'s length should be 39");
95    } else {
96        unreachable!();
97    }
98}
99
100#[test]
101fn create_token_not_ascii_str() {
102    let token = Token::try_create("pt-9749250e-d157-4f80-9ee2-359ce8524あ");
103    if let Err(error::Error::LocalError(err)) = token {
104        assert_eq!(err.as_str(), "token str should be ascii");
105    } else {
106        unreachable!();
107    }
108}
109
110struct TokenVisitor;
111
112impl<'de> Visitor<'de> for TokenVisitor {
113    type Value = Token;
114
115    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
116        formatter.write_str("a 39 length str")
117    }
118
119    fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
120    where
121        E: de::Error,
122    {
123        let token = Token::try_create(value);
124        if let Err(error::Error::LocalError(err)) = token {
125            return Err(E::custom(format!("fail to deserialize Token: {}", err)));
126        } else if let Err(_) = token {
127            return Err(E::custom(format!("fail to deserialize Token")));
128        }
129
130        Ok(token.unwrap())
131    }
132
133    fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
134    where
135        E: de::Error,
136    {
137        let token = Token::try_create(value);
138        if let Err(error::Error::LocalError(err)) = token {
139            return Err(E::custom(format!("fail to deserialize Token: {}", err)));
140        } else if let Err(_) = token {
141            return Err(E::custom(format!("fail to deserialize Token")));
142        }
143
144        Ok(token.unwrap())
145    }
146}
147
148impl<'de> Deserialize<'de> for Token {
149    fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
150    where
151        D: Deserializer<'de>,
152    {
153        deserializer.deserialize_identifier(TokenVisitor)
154    }
155}
156
157#[cfg(test)]
158mod deserialize_token {
159    use super::*;
160
161    #[derive(Deserialize)]
162    struct TokenWrapper {
163        pub token: Token,
164    }
165
166    #[test]
167    fn deserialize_ok() {
168        // this test is executed with 38 chars
169        let wrapper = serde_json::from_str::<TokenWrapper>(
170            r#"{"token": "pt-9749250e-d157-4f80-9ee2-359ce8524308"}"#,
171        )
172        .unwrap();
173        assert_eq!(
174            wrapper.token.as_str(),
175            "pt-9749250e-d157-4f80-9ee2-359ce8524308"
176        );
177    }
178
179    #[test]
180    fn deserialize_err() {
181        // this test is executed with 38 chars
182        let result = serde_json::from_str::<TokenWrapper>(
183            r#"{"token": "pt-9749250e-d157-4f80-9ee2-359ce852430"}"#,
184        );
185        assert!(result.is_err());
186    }
187}
188
189/// Pair of PeerId and Token.
190#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq, Eq, Ord, Hash)]
191pub struct PeerInfo {
192    peer_id: PeerId,
193    token: Token,
194}
195
196impl PeerInfo {
197    pub fn new(peer_id: PeerId, token: Token) -> Self {
198        Self { peer_id, token }
199    }
200
201    pub fn try_create(
202        peer_id: impl Into<String>,
203        token: impl Into<String>,
204    ) -> Result<Self, error::Error> {
205        Ok(PeerInfo {
206            peer_id: PeerId::new(peer_id),
207            token: Token::try_create(token)?,
208        })
209    }
210
211    pub fn peer_id(&self) -> PeerId {
212        return self.peer_id.clone();
213    }
214
215    pub fn token(&self) -> Token {
216        return self.token.clone();
217    }
218}
219
220/// Query for POST /peers.
221///
222/// [API](http://35.200.46.204/#/1.peers/peer)
223#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
224pub struct CreatePeerQuery {
225    /// SkyWay's API Key.
226    pub key: String,
227    /// Registered domain of the API Key
228    pub domain: String,
229    /// Peer Id that user want to use.
230    pub peer_id: PeerId,
231    /// Whether does user want to use TURN server or not.
232    pub turn: bool,
233}
234
235/// Response from POST /peers
236///
237/// [API](http://35.200.46.204/#/1.peers/peer)
238#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
239pub struct CreatedResponse {
240    /// Fixed value as `"PEERS_CREATE"`.
241    pub command_type: String,
242    /// Pair of PeerId and Token. PeerId is not allocated in the server in this timing.
243    pub params: PeerInfo,
244}
245
246/// Events from GET /peer/events
247#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
248#[serde(tag = "event")]
249pub(crate) enum EventEnum {
250    OPEN(PeerOpenEvent),
251    CLOSE(PeerCloseEvent),
252    CONNECTION(PeerConnectionEvent),
253    CALL(PeerCallEvent),
254    ERROR(PeerErrorEvent),
255    TIMEOUT,
256}
257
258/// Response from GET /peers/{peer_id}/events
259///
260/// [API](http://35.200.46.204/#/1.peers/peer_event)
261///
262/// Indicates peer object is registered to SkyWay Server
263#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
264pub struct PeerOpenEvent {
265    /// Pair of PeerId and Token. PeerId has been allocated in the server.
266    pub params: PeerInfo,
267}
268
269/// Response from GET /peers/{peer_id}/events
270///
271/// [API](http://35.200.46.204/#/1.peers/peer_event)
272///
273/// Indicates peer object is deleted
274#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
275pub struct PeerCloseEvent {
276    /// Pair of PeerId and Token. Just for indicating which Peer Object is deleted.
277    pub params: PeerInfo,
278}
279
280/// Response from GET /peers/{peer_id}/events
281///
282/// [API](http://35.200.46.204/#/1.peers/peer_event)
283///
284/// Shows Error about PeerObject
285#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
286pub struct PeerErrorEvent {
287    /// Pair of PeerId and Token. Indicate which Peer Object is regarded.
288    pub params: PeerInfo,
289    /// Shows detail of the error.
290    pub error_message: String,
291}
292
293/// Shows that the Peer Object receives a request to establish DataConnection with neighbour.
294///
295/// [API](http://35.200.46.204/#/1.peers/peer_event)
296///
297/// DataConnection is automatically established when the request comes.
298#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
299pub struct PeerConnectionEvent {
300    /// Pair of PeerId and Token. Indicate which Peer Object is regarded.
301    pub params: PeerInfo,
302    /// Id to identify the DataConnection
303    pub data_params: DataConnectionIdWrapper,
304}
305
306/// Shows that the Peer Object receives a request to establish MediaConnection with neighbour.
307///
308/// [API](http://35.200.46.204/#/1.peers/peer_event)
309#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
310pub struct PeerCallEvent {
311    pub params: PeerInfo,
312    pub call_params: MediaConnectionIdWrapper,
313}
314
315/// Response from GET /peer/{peer_id}/status
316///
317/// [API](http://35.200.46.204/#/1.peers/peer_status)
318#[derive(Serialize, Deserialize, Debug, Clone, PartialOrd, PartialEq)]
319pub struct PeerStatusMessage {
320    pub peer_id: PeerId,
321    pub disconnected: bool,
322}