1use std::io;
4
5use azalea_protocol::{
6 address::{ResolvableAddr, ServerAddr},
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 resolve,
20};
21use thiserror::Error;
22
23#[derive(Error, Debug)]
24pub enum PingError {
25 #[error("{0}")]
26 Resolve(#[from] resolve::ResolveError),
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 ResolvableAddr,
52) -> Result<ClientboundStatusResponse, PingError> {
53 let address = address.resolve().await?;
54 let conn = Connection::new(&address.socket).await?;
55 ping_server_with_connection(address.server, conn).await
56}
57
58pub async fn ping_server_with_proxy(
60 address: impl ResolvableAddr,
61 proxy: Proxy,
62) -> Result<ClientboundStatusResponse, PingError> {
63 let address = address.resolve().await?;
64 let conn = Connection::new_with_proxy(&address.socket, proxy).await?;
65 ping_server_with_connection(address.server, conn).await
66}
67
68pub async fn ping_server_with_connection(
73 address: ServerAddr,
74 mut conn: Connection<ClientboundHandshakePacket, ServerboundHandshakePacket>,
75) -> Result<ClientboundStatusResponse, PingError> {
76 conn.write(ServerboundIntention {
78 protocol_version: PROTOCOL_VERSION,
79 hostname: address.host.clone(),
80 port: address.port,
81 intention: ClientIntention::Status,
82 })
83 .await?;
84 let mut conn = conn.status();
85
86 conn.write(ServerboundStatusRequest {}).await?;
88
89 let packet = conn.read().await?;
90
91 loop {
92 match packet {
93 ClientboundStatusPacket::StatusResponse(p) => return Ok(p),
94 ClientboundStatusPacket::PongResponse(_) => {
95 }
97 }
98 }
99}