rings_transport/
ice_server.rs1use std::str::FromStr;
4
5use serde::Deserialize;
6use serde::Serialize;
7use url::Url;
8
9use crate::error::IceServerError;
10
11#[derive(Deserialize, Serialize, Debug, Clone, Default, PartialEq, Eq)]
13pub enum IceCredentialType {
14 #[default]
17 Password,
18
19 Oauth,
23}
24
25#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
31pub struct IceServer {
32 pub urls: Vec<String>,
34 pub username: String,
36 pub credential: String,
38 pub credential_type: IceCredentialType,
40}
41
42impl IceServer {
43 pub fn vec_from_str(s: &str) -> Result<Vec<Self>, IceServerError> {
45 s.split(';').map(IceServer::from_str).collect()
46 }
47}
48
49impl Default for IceServer {
50 fn default() -> Self {
51 Self {
52 urls: ["stun://stun.l.google.com:19302".to_string()].to_vec(),
53 username: String::default(),
54 credential: String::default(),
55 credential_type: IceCredentialType::default(),
56 }
57 }
58}
59
60impl FromStr for IceServer {
66 type Err = IceServerError;
67 fn from_str(s: &str) -> Result<Self, IceServerError> {
68 let parsed = Url::parse(s)?;
69 let scheme = parsed.scheme();
70 if !(["turn", "stun"].contains(&scheme)) {
71 return Err(IceServerError::SchemeNotSupported(scheme.into()));
72 }
73 if !parsed.has_host() {
74 return Err(IceServerError::UrlMissHost);
75 }
76 let username = parsed.username();
77 let password = parsed.password().unwrap_or("");
78 let host = parsed.host_str().unwrap();
80 let port = parsed
82 .port()
83 .map(|p| format!(":{}", p))
84 .unwrap_or_else(|| "".to_string());
85 let path = parsed.path();
86 let url = format!("{}:{}{}{}", scheme, host, port, path);
87 Ok(Self {
88 urls: vec![url],
89 username: username.to_string(),
90 credential: password.to_string(),
91 credential_type: IceCredentialType::default(),
92 })
93 }
94}
95
96#[cfg(test)]
97mod test {
98 use std::str::FromStr;
99
100 use super::IceServer;
101
102 #[test]
103 fn test_parsing() {
104 let a = "stun://foo:bar@stun.l.google.com:19302";
105 let b = "turn://ethereum.org:9090";
106 let c = "turn://ryan@ethereum.org:9090/nginx/v2";
107 let d = "turn://ryan@ethereum.org/nginx/v2";
108 let e = "http://ryan@ethereum.org/nginx/v2";
109 let ret_a = IceServer::from_str(a).unwrap();
110 let ret_b = IceServer::from_str(b).unwrap();
111 let ret_c = IceServer::from_str(c).unwrap();
112 let ret_d = IceServer::from_str(d).unwrap();
113 let ret_e = IceServer::from_str(e);
114
115 assert_eq!(ret_a.urls[0], "stun:stun.l.google.com:19302".to_string());
116 assert_eq!(ret_a.credential, "bar".to_string());
117 assert_eq!(ret_a.username, "foo".to_string());
118
119 assert_eq!(ret_b.urls[0], "turn:ethereum.org:9090".to_string());
120 assert_eq!(ret_b.credential, "".to_string());
121 assert_eq!(ret_b.username, "".to_string());
122
123 assert_eq!(ret_c.urls[0], "turn:ethereum.org:9090/nginx/v2".to_string());
124 assert_eq!(ret_c.credential, "".to_string());
125 assert_eq!(ret_c.username, "ryan".to_string());
126
127 assert_eq!(ret_d.urls[0], "turn:ethereum.org/nginx/v2".to_string());
128 assert_eq!(ret_d.credential, "".to_string());
129 assert_eq!(ret_d.username, "ryan".to_string());
130
131 assert!(ret_e.is_err());
132 }
133}