1use std::io;
4
5use azalea_protocol::{
6 ServerAddress,
7 connect::{Connection, ConnectionError, Proxy},
8 packets::{
9 ClientIntention, PROTOCOL_VERSION,
10 handshake::{
11 ClientboundHandshakePacket, ServerboundHandshakePacket,
12 s_intention::ServerboundIntention,
13 },
14 status::{
15 ClientboundStatusPacket, c_status_response::ClientboundStatusResponse,
16 s_status_request::ServerboundStatusRequest,
17 },
18 },
19 resolver,
20};
21use thiserror::Error;
22
23#[derive(Error, Debug)]
24pub enum PingError {
25 #[error("{0}")]
26 Resolver(#[from] resolver::ResolverError),
27 #[error("{0}")]
28 Connection(#[from] ConnectionError),
29 #[error("{0}")]
30 ReadPacket(#[from] Box<azalea_protocol::read::ReadPacketError>),
31 #[error("{0}")]
32 WritePacket(#[from] io::Error),
33 #[error("The given address could not be parsed into a ServerAddress")]
34 InvalidAddress,
35}
36
37pub async fn ping_server(
51 address: impl TryInto<ServerAddress>,
52) -> Result<ClientboundStatusResponse, PingError> {
53 let address: ServerAddress = address.try_into().map_err(|_| PingError::InvalidAddress)?;
54 let resolved_address = resolver::resolve_address(&address).await?;
55 let conn = Connection::new(&resolved_address).await?;
56 ping_server_with_connection(address, conn).await
57}
58
59pub async fn ping_server_with_proxy(
61 address: impl TryInto<ServerAddress>,
62 proxy: Proxy,
63) -> Result<ClientboundStatusResponse, PingError> {
64 let address: ServerAddress = address.try_into().map_err(|_| PingError::InvalidAddress)?;
65 let resolved_address = resolver::resolve_address(&address).await?;
66 let conn = Connection::new_with_proxy(&resolved_address, proxy).await?;
67 ping_server_with_connection(address, conn).await
68}
69
70pub async fn ping_server_with_connection(
74 address: ServerAddress,
75 mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
76) -> Result<ClientboundStatusResponse, PingError> {
77 conn.write(ServerboundIntention {
79 protocol_version: PROTOCOL_VERSION,
80 hostname: address.host.clone(),
81 port: address.port,
82 intention: ClientIntention::Status,
83 })
84 .await?;
85 let mut conn = conn.status();
86
87 conn.write(ServerboundStatusRequest {}).await?;
89
90 let packet = conn.read().await?;
91
92 loop {
93 match packet {
94 ClientboundStatusPacket::StatusResponse(p) => return Ok(p),
95 ClientboundStatusPacket::PongResponse(_) => {
96 }
98 }
99 }
100}