ddapi_rs/util/
tw_addr.rs

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