veloren_query_server/
client.rs1use std::{
2 io,
3 net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
4 time::{Duration, Instant},
5};
6
7use protocol::Parcel;
8use tokio::{net::UdpSocket, time::timeout};
9use tracing::trace;
10
11use crate::proto::{
12 QueryServerRequest, QueryServerResponse, RawQueryServerRequest, RawQueryServerResponse,
13 ServerInfo, MAX_RESPONSE_SIZE,
14};
15
16const MAX_REQUEST_RETRIES: usize = 5;
18
19#[derive(Debug)]
20pub enum QueryClientError {
21 Io(tokio::io::Error),
22 Protocol(protocol::Error),
23 InvalidResponse,
24 Timeout,
25 ChallengeFailed,
26}
27
28struct ClientInitData {
29 p: u64,
30 #[allow(dead_code)]
31 server_max_version: u16,
32}
33
34pub struct QueryClient {
37 pub addr: SocketAddr,
38 init: Option<ClientInitData>,
39}
40
41impl QueryClient {
42 pub fn new(addr: SocketAddr) -> Self { Self { addr, init: None } }
43
44 pub async fn server_info(&mut self) -> Result<(ServerInfo, Duration), QueryClientError> {
45 self.send_query(QueryServerRequest::ServerInfo)
46 .await
47 .and_then(|(response, duration)| {
48 #[allow(irrefutable_let_patterns)]
49 if let QueryServerResponse::ServerInfo(info) = response {
50 Ok((info, duration))
51 } else {
52 Err(QueryClientError::InvalidResponse)
53 }
54 })
55 }
56
57 async fn send_query(
58 &mut self,
59 request: QueryServerRequest,
60 ) -> Result<(QueryServerResponse, Duration), QueryClientError> {
61 let socket = UdpSocket::bind(if self.addr.is_ipv4() {
62 SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0))
63 } else {
64 SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::UNSPECIFIED, 0, 0, 0))
65 })
66 .await?;
67
68 for _ in 0..MAX_REQUEST_RETRIES {
69 let request = if let Some(init) = &self.init {
70 RawQueryServerRequest { p: init.p, request }
73 } else {
74 RawQueryServerRequest {
76 p: 0,
77 request: QueryServerRequest::Init,
78 }
79 };
80 let buf = request.serialize()?;
81 let query_sent = Instant::now();
82 socket.send_to(&buf, self.addr).await?;
83 let mut buf = vec![0; MAX_RESPONSE_SIZE];
84 let (buf_len, _) = timeout(Duration::from_secs(2), socket.recv_from(&mut buf))
85 .await
86 .map_err(|_| QueryClientError::Timeout)??;
87
88 if buf_len <= 2 {
89 Err(QueryClientError::InvalidResponse)?
90 }
91
92 let packet = <RawQueryServerResponse as Parcel>::read(
93 &mut io::Cursor::new(&buf[..buf_len]),
94 &Default::default(),
95 )?;
96
97 match packet {
98 RawQueryServerResponse::Response(response) => {
99 return Ok((response, query_sent.elapsed()));
100 },
101 RawQueryServerResponse::Init(init) => {
102 trace!(?init, "Resetting p");
103 self.init = Some(ClientInitData {
104 p: init.p,
105 server_max_version: init.max_supported_version,
106 });
107 },
108 }
109 }
110
111 Err(QueryClientError::ChallengeFailed)
112 }
113}
114
115impl From<tokio::io::Error> for QueryClientError {
116 fn from(value: tokio::io::Error) -> Self { Self::Io(value) }
117}
118
119impl From<protocol::Error> for QueryClientError {
120 fn from(value: protocol::Error) -> Self { Self::Protocol(value) }
121}