azalea_protocol/
address.rs

1use std::{
2    fmt::{self, Debug, Display},
3    net::SocketAddr,
4    str::FromStr,
5};
6
7use hickory_resolver::ResolveError;
8
9use crate::resolve::resolve_address;
10
11/// Something that might be able to be parsed and looked up as a server address.
12///
13/// This is typically used by Azalea as a generic argument, so the user can
14/// choose to pass either a string or an already-resolved address.
15pub trait ResolvableAddr: Debug + Clone {
16    fn server_addr(self) -> Result<ServerAddr, ResolveError>;
17    fn resolve(self) -> impl Future<Output = Result<ResolvedAddr, ResolveError>> + Send;
18}
19impl<T: TryInto<ServerAddr, Error = ServerAddrParseError> + Debug + Send + Clone> ResolvableAddr
20    for T
21{
22    fn server_addr(self) -> Result<ServerAddr, ResolveError> {
23        self.try_into()
24            .map_err(|_| "failed to parse address".into())
25    }
26
27    async fn resolve(self) -> Result<ResolvedAddr, ResolveError> {
28        ResolvedAddr::new(self.server_addr()?).await
29    }
30}
31
32impl ResolvableAddr for &ResolvedAddr {
33    fn server_addr(self) -> Result<ServerAddr, ResolveError> {
34        Ok(self.server.clone())
35    }
36
37    async fn resolve(self) -> Result<ResolvedAddr, ResolveError> {
38        Ok(self.clone())
39    }
40}
41
42/// A host and port. It's possible that the port doesn't resolve to anything.
43///
44/// # Examples
45///
46/// `ServerAddr` implements TryFrom<&str>, so you can use it like this:
47/// ```
48/// use azalea_protocol::address::ServerAddr;
49///
50/// let addr = ServerAddr::try_from("localhost:25565").unwrap();
51/// assert_eq!(addr.host, "localhost");
52/// assert_eq!(addr.port, 25565);
53/// ```
54#[derive(Debug, Clone, PartialEq, Eq, Hash)]
55pub struct ServerAddr {
56    pub host: String,
57    pub port: u16,
58}
59
60/// An empty error type that's used when we fail to convert a type to a
61/// `ServerAddr`.
62///
63/// You usually want to use the [`ResolvableAddr`] type instead, which works
64/// with [`ResolveError`]s.
65#[derive(Debug)]
66pub struct ServerAddrParseError;
67
68impl TryFrom<&str> for ServerAddr {
69    type Error = ServerAddrParseError;
70
71    /// Convert a Minecraft server address (`host:port`, the port is optional)
72    /// to a `ServerAddress`
73    fn try_from(string: &str) -> Result<Self, Self::Error> {
74        if string.is_empty() {
75            return Err(ServerAddrParseError);
76        }
77        let mut parts = string.split(':');
78        let host = parts.next().ok_or(ServerAddrParseError)?.to_owned();
79        // default the port to 25565
80        let port = parts.next().unwrap_or("25565");
81        let port = u16::from_str(port).ok().ok_or(ServerAddrParseError)?;
82        Ok(ServerAddr { host, port })
83    }
84}
85impl TryFrom<String> for ServerAddr {
86    type Error = ServerAddrParseError;
87
88    fn try_from(string: String) -> Result<Self, Self::Error> {
89        ServerAddr::try_from(string.as_str())
90    }
91}
92
93impl From<SocketAddr> for ServerAddr {
94    /// Convert an existing `SocketAddr` into a `ServerAddress`.
95    ///
96    /// This just converts the IP to a string and passes along the port. The
97    /// resolver will realize it's already an IP address and not do any DNS
98    /// requests.
99    fn from(addr: SocketAddr) -> Self {
100        ServerAddr {
101            host: addr.ip().to_string(),
102            port: addr.port(),
103        }
104    }
105}
106
107impl Display for ServerAddr {
108    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109        write!(f, "{}:{}", self.host, self.port)
110    }
111}
112
113/// Serde deserialization for ServerAddress.
114///
115/// This is useful if you're storing the server address in a config file.
116impl<'de> serde::Deserialize<'de> for ServerAddr {
117    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
118    where
119        D: serde::Deserializer<'de>,
120    {
121        let string = String::deserialize(deserializer)?;
122        ServerAddr::try_from(string.as_str())
123            .map_err(|_| serde::de::Error::custom("failed to parse address"))
124    }
125}
126
127/// Serde serialization for ServerAddress.
128///
129/// This uses the Display impl, so it will serialize to a string.
130impl serde::Serialize for ServerAddr {
131    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
132    where
133        S: serde::Serializer,
134    {
135        serializer.serialize_str(&self.to_string())
136    }
137}
138
139/// An address that may be used to connect to a Minecraft server.
140#[derive(Debug, Clone)]
141pub struct ResolvedAddr {
142    /// The initial address that we passed when trying to connect.
143    ///
144    /// This is necessary because clients send this to the server when they
145    /// connect.
146    pub server: ServerAddr,
147    /// The IP and port that we will actually connect to.
148    pub socket: SocketAddr,
149}
150
151impl ResolvedAddr {
152    pub async fn new(server: impl Into<ServerAddr>) -> Result<Self, ResolveError> {
153        let server = server.into();
154        let socket = resolve_address(&server).await?;
155        Ok(Self { server, socket })
156    }
157}