Skip to main content

azalea_protocol/
address.rs

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