1use serde::{Deserialize, Serialize};
2use std::net::IpAddr;
3
4#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
14pub struct Addr {
15 pub ip: IpAddr,
16 pub port: u16,
17 pub protocol: Protocol,
18}
19
20#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize)]
29pub enum Protocol {
30 V5,
31 V6,
32 V7,
33 VPg,
34}
35
36impl Protocol {
37 pub fn as_str(&self) -> &'static str {
38 match self {
39 Protocol::V5 => "tw-0.5+udp",
40 Protocol::V6 => "tw-0.6+udp",
41 Protocol::V7 => "tw-0.7+udp",
42 Protocol::VPg => "ddrs-0.1+quic",
43 }
44 }
45}
46
47impl From<&str> for Protocol {
48 fn from(s: &str) -> Self {
49 Protocol::try_from_str(s).unwrap_or_else(|e| panic!("{e}"))
50 }
51}
52
53impl std::fmt::Display for Protocol {
54 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55 write!(f, "{}", self.as_str())
56 }
57}
58
59impl Protocol {
60 pub fn try_from_str(value: &str) -> Result<Self, String> {
61 match value {
62 "tw-0.5+udp" => Ok(Protocol::V5),
63 "tw-0.6+udp" => Ok(Protocol::V6),
64 "tw-0.7+udp" => Ok(Protocol::V7),
65 "ddrs-0.1+quic" => Ok(Protocol::VPg),
66 _ => Err(format!("Unknown protocol: {value}")),
67 }
68 }
69}
70
71impl TryFrom<&str> for Addr {
72 type Error = String;
73
74 fn try_from(url: &str) -> Result<Self, Self::Error> {
75 let (protocol_str, host_port) = url.split_once("://").ok_or_else(|| {
76 format!(
77 "Invalid URL format, expected 'protocol://host:port', got: {}",
78 url
79 )
80 })?;
81
82 let protocol = Protocol::try_from_str(protocol_str)?;
83
84 let (host, port_str) = if let Some(rest) = host_port.strip_prefix('[') {
85 let (host, rest) = rest.split_once(']').ok_or_else(|| {
86 format!(
87 "Invalid IPv6 format, expected '[host]:port', got: {}",
88 host_port
89 )
90 })?;
91 let port_str = rest.strip_prefix(':').ok_or_else(|| {
92 format!(
93 "Invalid IPv6 port format, expected ']:port', got: {}",
94 host_port
95 )
96 })?;
97 (host, port_str)
98 } else {
99 host_port.split_once(':').ok_or_else(|| {
100 format!(
101 "Invalid host:port format, expected 'host:port', got: {}",
102 host_port
103 )
104 })?
105 };
106
107 let ip: IpAddr = host
108 .parse()
109 .map_err(|e| format!("Failed to parse IP '{}': {}", host, e))?;
110
111 let port: u16 = port_str
112 .parse()
113 .map_err(|e| format!("Failed to parse port '{}': {}", port_str, e))?;
114
115 Ok(Addr { ip, port, protocol })
116 }
117}
118
119pub mod addr_serialization {
120 use super::*;
121 use serde::{Deserialize, Deserializer, Serializer};
122
123 pub fn serialize<S>(addrs: &[Addr], serializer: S) -> Result<S::Ok, S::Error>
124 where
125 S: Serializer,
126 {
127 use serde::ser::SerializeSeq;
128
129 let mut seq = serializer.serialize_seq(Some(addrs.len()))?;
130 for addr in addrs {
131 let url = format!("{}://{}:{}", addr.protocol.as_str(), addr.ip, addr.port);
132 seq.serialize_element(&url)?;
133 }
134 seq.end()
135 }
136
137 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<Addr>, D::Error>
138 where
139 D: Deserializer<'de>,
140 {
141 use serde::de::Error;
142
143 let string_vec: Vec<String> = Vec::deserialize(deserializer)?;
144 let mut addrs = Vec::with_capacity(string_vec.len());
145
146 for s in string_vec {
147 match Addr::try_from(s.as_str()) {
148 Ok(addr) => addrs.push(addr),
149 Err(e) => {
150 return Err(D::Error::custom(format!(
151 "Failed to parse address '{}': {}",
152 s, e
153 )))
154 }
155 }
156 }
157
158 Ok(addrs)
159 }
160}