p2p/webrtc/signaling_method/
mod.rs1mod http;
2pub use http::HttpSignalingInfo;
3
4use std::{fmt, str::FromStr};
5
6use binprot_derive::{BinProtRead, BinProtWrite};
7use serde::{Deserialize, Serialize};
8use thiserror::Error;
9
10use crate::PeerId;
11
12#[derive(BinProtWrite, BinProtRead, Eq, PartialEq, Ord, PartialOrd, Debug, Clone)]
13pub enum SignalingMethod {
14 Http(HttpSignalingInfo),
15 Https(HttpSignalingInfo),
16 HttpsProxy(u16, HttpSignalingInfo),
18 P2p {
19 relay_peer_id: PeerId,
20 },
21}
22
23impl SignalingMethod {
24 pub fn can_connect_directly(&self) -> bool {
25 match self {
26 Self::Http(_) | Self::Https(_) | Self::HttpsProxy(_, _) => true,
27 Self::P2p { .. } => false,
28 }
29 }
30
31 pub fn http_url(&self) -> Option<String> {
34 let (http, info) = match self {
35 Self::Http(info) => ("http", info),
36 Self::Https(info) => ("https", info),
37 Self::HttpsProxy(cluster_id, info) => {
38 return Some(format!(
39 "https://{}:{}/clusters/{}/mina/webrtc/signal",
40 info.host, info.port, cluster_id
41 ));
42 }
43 _ => return None,
44 };
45 Some(format!(
46 "{http}://{}:{}/mina/webrtc/signal",
47 info.host, info.port,
48 ))
49 }
50
51 pub fn p2p_relay_peer_id(&self) -> Option<PeerId> {
52 match self {
53 Self::P2p { relay_peer_id } => Some(*relay_peer_id),
54 _ => None,
55 }
56 }
57}
58
59impl fmt::Display for SignalingMethod {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 match self {
62 Self::Http(signaling) => {
63 write!(f, "/http")?;
64 signaling.fmt(f)
65 }
66 Self::Https(signaling) => {
67 write!(f, "/https")?;
68 signaling.fmt(f)
69 }
70 Self::HttpsProxy(cluster_id, signaling) => {
71 write!(f, "/https_proxy/{cluster_id}")?;
72 signaling.fmt(f)
73 }
74 Self::P2p { relay_peer_id } => {
75 write!(f, "/p2p/{relay_peer_id}")
76 }
77 }
78 }
79}
80
81#[derive(Error, Serialize, Deserialize, Debug, Clone)]
82pub enum SignalingMethodParseError {
83 #[error("not enough args for the signaling method")]
84 NotEnoughArgs,
85 #[error("unknown signaling method: `{0}`")]
86 UnknownSignalingMethod(String),
87 #[error("invalid cluster id")]
88 InvalidClusterId,
89 #[error("host parse error: {0}")]
90 HostParseError(String),
91 #[error("host parse error: {0}")]
92 PortParseError(String),
93}
94
95impl FromStr for SignalingMethod {
96 type Err = SignalingMethodParseError;
97
98 fn from_str(s: &str) -> Result<Self, Self::Err> {
99 if s.is_empty() {
100 return Err(SignalingMethodParseError::NotEnoughArgs);
101 }
102
103 let method_end_index = s[1..]
104 .find('/')
105 .map(|i| i + 1)
106 .filter(|i| s.len() > *i)
107 .ok_or(SignalingMethodParseError::NotEnoughArgs)?;
108
109 let rest = &s[method_end_index..];
110 match &s[1..method_end_index] {
111 "http" => Ok(Self::Http(rest.parse()?)),
112 "https" => Ok(Self::Https(rest.parse()?)),
113 "https_proxy" => {
114 let mut iter = rest.splitn(3, '/').filter(|v| !v.trim().is_empty());
115 let (cluster_id, rest) = (
116 iter.next()
117 .ok_or(SignalingMethodParseError::NotEnoughArgs)?,
118 iter.next()
119 .ok_or(SignalingMethodParseError::NotEnoughArgs)?,
120 );
121 let cluster_id: u16 = cluster_id
122 .parse()
123 .or(Err(SignalingMethodParseError::InvalidClusterId))?;
124 Ok(Self::HttpsProxy(cluster_id, rest.parse()?))
125 }
126 method => Err(SignalingMethodParseError::UnknownSignalingMethod(
127 method.to_owned(),
128 )),
129 }
130 }
131}
132
133impl Serialize for SignalingMethod {
134 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
135 where
136 S: serde::Serializer,
137 {
138 serializer.serialize_str(&self.to_string())
139 }
140}
141
142impl<'de> serde::Deserialize<'de> for SignalingMethod {
143 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
144 where
145 D: serde::Deserializer<'de>,
146 {
147 let s: String = Deserialize::deserialize(deserializer)?;
148 s.parse().map_err(serde::de::Error::custom)
149 }
150}