11use actix_web:: web:: Buf ;
22use byteorder:: { LittleEndian , ReadBytesExt } ;
3+ use once_cell:: sync:: Lazy ;
34use regex:: Regex ;
45use serde:: { Deserialize , Serialize } ;
5- use std:: io:: { Cursor , Read } ;
6+ use std:: collections:: HashMap ;
7+ use std:: io:: { Cursor , Error , ErrorKind , Read } ;
8+ use std:: sync:: Mutex ;
9+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
610use std:: { net:: Ipv4Addr , time:: Duration } ;
711use tokio:: net:: { lookup_host, UdpSocket } ;
812use tokio:: time:: timeout_at;
913use tokio:: time:: Instant ;
1014
1115use crate :: helpers;
1216
17+ static OMP_EXTRA_INFO_LAST_UPDATE_LIST : Lazy < Mutex < HashMap < String , u64 > > > =
18+ Lazy :: new ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
19+ const OMP_EXTRA_INFO_UPDATE_COOLDOWN_SECS : u64 = 3 ;
20+
1321pub struct Query {
1422 address : Ipv4Addr ,
1523 port : i32 ,
@@ -40,6 +48,21 @@ pub struct ExtraInfoPacket {
4048 pub logo_url : String ,
4149}
4250
51+ #[ derive( Serialize , Deserialize , Clone , Default ) ]
52+ pub struct ServerQueryResponse {
53+ pub info : Option < String > ,
54+ pub extra_info : Option < String > ,
55+ pub players : Option < String > ,
56+ pub rules : Option < String > ,
57+ pub ping : Option < u32 > ,
58+ }
59+
60+ #[ derive( Serialize , Deserialize , Clone , Default ) ]
61+ pub struct ErrorResponse {
62+ pub info : String ,
63+ pub error : bool ,
64+ }
65+
4366impl Query {
4467 pub async fn new ( addr : & str , port : i32 ) -> Result < Self , std:: io:: Error > {
4568 let regex = Regex :: new ( r"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$" ) . unwrap ( ) ;
@@ -119,7 +142,7 @@ impl Query {
119142 } ;
120143
121144 if amt == 0 {
122- return Ok ( String :: from ( "no_data" ) ) ;
145+ return Err ( Error :: new ( ErrorKind :: Other , String :: from ( "no_data" ) ) ) ;
123146 }
124147
125148 let query_type = buf[ 10 ] as char ;
@@ -135,7 +158,7 @@ impl Query {
135158 } else if query_type == 'p' {
136159 Ok ( String :: from ( "pong" ) )
137160 } else {
138- Ok ( String :: from ( "no_data" ) )
161+ Err ( Error :: new ( ErrorKind :: Other , String :: from ( "no_data" ) ) )
139162 }
140163 }
141164
@@ -238,3 +261,118 @@ impl Query {
238261 Ok ( serde_json:: to_string ( & rules) . unwrap ( ) )
239262 }
240263}
264+
265+ #[ tauri:: command]
266+ pub async fn query_server (
267+ ip : & str ,
268+ port : i32 ,
269+ info : bool ,
270+ extra_info : bool ,
271+ players : bool ,
272+ rules : bool ,
273+ ping : bool ,
274+ ) -> Result < String , String > {
275+ match Query :: new ( ip, port) . await {
276+ Ok ( q) => {
277+ let mut result = ServerQueryResponse {
278+ info : None ,
279+ extra_info : None ,
280+ players : None ,
281+ rules : None ,
282+ ping : None ,
283+ } ;
284+
285+ if info {
286+ let _ = q. send ( 'i' ) . await ;
287+ result. info = Some ( match q. recv ( ) . await {
288+ Ok ( p) => format ! ( "{}" , p) ,
289+ Err ( e) => {
290+ let mut error_details = ErrorResponse :: default ( ) ;
291+ error_details. error = true ;
292+ error_details. info = e. to_string ( ) ;
293+ serde_json:: to_string ( & error_details) . unwrap ( )
294+ }
295+ } ) ;
296+ }
297+
298+ if players {
299+ let _ = q. send ( 'c' ) . await ;
300+ result. players = Some ( match q. recv ( ) . await {
301+ Ok ( p) => format ! ( "{}" , p) ,
302+ Err ( e) => {
303+ let mut error_details = ErrorResponse :: default ( ) ;
304+ error_details. error = true ;
305+ error_details. info = e. to_string ( ) ;
306+ serde_json:: to_string ( & error_details) . unwrap ( )
307+ }
308+ } ) ;
309+ }
310+
311+ if rules {
312+ let _ = q. send ( 'r' ) . await ;
313+ result. rules = Some ( match q. recv ( ) . await {
314+ Ok ( p) => format ! ( "{}" , p) ,
315+ Err ( e) => {
316+ let mut error_details = ErrorResponse :: default ( ) ;
317+ error_details. error = true ;
318+ error_details. info = e. to_string ( ) ;
319+ serde_json:: to_string ( & error_details) . unwrap ( )
320+ }
321+ } ) ;
322+ }
323+
324+ if extra_info {
325+ let now = SystemTime :: now ( )
326+ . duration_since ( UNIX_EPOCH )
327+ . unwrap ( )
328+ . as_secs ( ) ;
329+
330+ let key = format ! ( "{}:{}" , ip, port) ;
331+
332+ let should_request = {
333+ let mut map = OMP_EXTRA_INFO_LAST_UPDATE_LIST . lock ( ) . unwrap ( ) ;
334+ match map. get ( & key) {
335+ Some ( & last_time)
336+ if now - last_time < OMP_EXTRA_INFO_UPDATE_COOLDOWN_SECS =>
337+ {
338+ false
339+ }
340+ _ => {
341+ map. insert ( key. clone ( ) , now) ;
342+ true
343+ }
344+ }
345+ } ;
346+
347+ if should_request {
348+ let _ = q. send ( 'o' ) . await ;
349+ result. extra_info = Some ( match q. recv ( ) . await {
350+ Ok ( p) => format ! ( "{}" , p) ,
351+ Err ( e) => {
352+ let mut error_details = ErrorResponse :: default ( ) ;
353+ error_details. error = true ;
354+ error_details. info = e. to_string ( ) ;
355+ serde_json:: to_string ( & error_details) . unwrap ( )
356+ }
357+ } ) ;
358+ }
359+ }
360+
361+ if ping {
362+ let _ = q. send ( 'p' ) . await ;
363+ let before = Instant :: now ( ) ;
364+ match q. recv ( ) . await {
365+ Ok ( _p) => {
366+ result. ping = Some ( before. elapsed ( ) . as_millis ( ) as u32 ) ;
367+ }
368+ Err ( _) => {
369+ result. ping = Some ( 9999 ) ;
370+ }
371+ }
372+ }
373+
374+ Ok ( serde_json:: to_string ( & result) . unwrap ( ) )
375+ }
376+ Err ( e) => Err ( e. to_string ( ) ) ,
377+ }
378+ }
0 commit comments