1pub use models::info::Info;
16pub use models::info::Platform;
17pub use models::info::ServerType;
18pub use models::info::Vac;
19pub use models::info::Visibility;
20pub use models::Player;
21pub use server::Rules;
22pub use server::Server;
23
24#[allow(dead_code)]
25const ENCODING: &str = "utf-8";
26const PACKET_SIZE: usize = 1400;
27const SIMPLE_RESPONSE_HEADER: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFF];
29const MULTI_PACKET_RESPONSE_HEADER: [u8; 4] = [0xFF, 0xFF, 0xFF, 0xFE];
31
32pub mod types {
34
35 pub type Byte = u8;
37 pub type Short = i16;
38 pub type Long = i32;
39 pub type Float = f32;
40 pub type LongLong = u64;
41 pub type CString = std::ffi::CString;
42
43 pub enum DataType {
45 Byte(Byte),
54 Short(Short),
55 Long(i32),
56 Float(f32),
57 LongLong(u64),
58 String(CString),
61 }
62
63 pub fn get_byte<'a, I>(bytes: &mut I) -> Byte
64 where
65 I: Iterator<Item = &'a u8>,
66 {
67 bytes.next().expect("the next byte exists").to_owned()
68 }
69 pub fn get_short<'a, I>(bytes: &mut I) -> Short
70 where
71 I: Iterator<Item = &'a u8>,
72 {
73 Short::from_le_bytes([
74 *bytes.next().expect("next byte exists"),
75 *bytes.next().expect("next byte exists"),
76 ])
77 }
78 pub fn get_long<'a, I>(bytes: &mut I) -> Long
79 where
80 I: Iterator<Item = &'a u8>,
81 {
82 Long::from_le_bytes([
83 *bytes.next().expect("next byte exists"),
84 *bytes.next().expect("next byte exists"),
85 *bytes.next().expect("next byte exists"),
86 *bytes.next().expect("next byte exists"),
87 ])
88 }
89 pub fn get_float<'a, I>(bytes: &mut I) -> Float
90 where
91 I: Iterator<Item = &'a u8>,
92 {
93 Float::from_le_bytes([
94 *bytes.next().expect("next byte exists"),
95 *bytes.next().expect("next byte exists"),
96 *bytes.next().expect("next byte exists"),
97 *bytes.next().expect("next byte exists"),
98 ])
99 }
100 pub fn get_longlong<'a, I>(bytes: &mut I) -> LongLong
101 where
102 I: Iterator<Item = &'a u8>,
103 {
104 LongLong::from_le_bytes([
105 *bytes.next().expect("next byte exists"),
106 *bytes.next().expect("next byte exists"),
107 *bytes.next().expect("next byte exists"),
108 *bytes.next().expect("next byte exists"),
109 *bytes.next().expect("next byte exists"),
110 *bytes.next().expect("next byte exists"),
111 *bytes.next().expect("next byte exists"),
112 *bytes.next().expect("next byte exists"),
113 ])
114 }
115 pub fn get_string<'a, I>(bytes: &mut I) -> String
116 where
117 I: Iterator<Item = &'a u8>,
118 {
119 let mut string = String::new();
120 loop {
121 let byte = bytes.next().expect("next byte exists");
122 if *byte == 0 {
123 break;
124 } else {
125 string.push(*byte as char);
126 }
127 }
128 string
129 }
130}
131
132pub mod models {
133
134 use crate::types::{get_byte, get_float, get_long, get_string, Byte, Float, Long};
135
136 #[derive(Debug, PartialEq, Clone)]
137 pub struct Player {
138 index: Byte,
139 name: String,
140 score: Long,
141 duration: Float,
142 }
143
144 impl Default for Player {
145 fn default() -> Self {
146 Self {
147 index: 0,
148 name: "".to_string(),
149 score: 0,
150 duration: 0.0,
151 }
152 }
153 }
154
155 impl Player {
157 pub fn name(&self) -> &str {
158 &self.name
159 }
160 pub fn score(&self) -> Long {
161 self.score
162 }
163 pub fn duration(&self) -> Float {
164 self.duration
165 }
166 }
167
168 impl Player {
169 pub fn get_players(bytes: &[u8]) -> Vec<Self> {
170 let mut it = bytes.iter();
171 let mut players: Vec<Self> = Vec::new();
172
173 while it.len()
174 > (
175 std::mem::size_of::<Byte>()
177 + std::mem::size_of::<Long>()
178 + std::mem::size_of::<Float>()
179 )
180 {
181 let player = Self::from_iter_bytes(&mut it);
182
183 players.push(player);
184 }
185
186 players
187 }
188
189 pub fn from_iter_bytes<'a, I>(iter_bytes: &mut I) -> Self
190 where
191 I: Iterator<Item = &'a u8>,
192 {
193 let index = get_byte(iter_bytes);
194 let name = get_string(iter_bytes);
195 let score = get_long(iter_bytes);
196 let duration = get_float(iter_bytes);
197
198 Self {
199 index,
200 name,
201 score,
202 duration,
203 }
204 }
205
206 pub fn from_bytes(bytes: &[u8]) -> Self {
207 let mut it = bytes.iter();
208
209 let index = get_byte(&mut it);
210 let name = get_string(&mut it);
211 let score = get_long(&mut it);
212 let duration = get_float(&mut it);
213
214 Self {
215 index,
216 name,
217 score,
218 duration,
219 }
220 }
221 }
222
223 pub mod info {
224
225 use crate::types::{Byte, LongLong, Short};
226
227 #[derive(Debug, PartialEq, Clone)]
238 pub struct Info {
239 header: Byte,
241 protocol: Byte,
243 name: String,
245 map: String,
247 folder: String,
249 game: String,
251 id: Short,
253 players: Byte,
255 max_players: Byte,
257 bots: Byte,
259 server_type: ServerType,
264 environment: Platform,
269 visibility: Visibility,
273 vac: Vac,
277 game_version: String,
279 extra_data_flag: Option<Byte>,
281 port: Option<Short>,
283 steam_id: Option<LongLong>,
285 spectator_port: Option<Short>,
287 spectator_name: Option<String>,
289 keywords: Option<String>,
291 game_id: Option<LongLong>,
295 trailing_bytes: Option<Vec<Byte>>,
297 }
298
299 impl Info {
300 pub fn from_bytes(bytes: &[u8]) -> Self {
301 use crate::types::get_byte;
302 use crate::types::get_longlong;
303 use crate::types::get_short;
304 use crate::types::get_string;
305 use crate::utils::compress_trailing_null_bytes;
306
307 let mut it = bytes.iter();
308
309 let header = get_byte(&mut it);
310 let protocol = get_byte(&mut it);
311 let name = get_string(&mut it);
312 let map = get_string(&mut it);
313 let folder = get_string(&mut it);
314 let game = get_string(&mut it);
315 let id = get_short(&mut it);
316 let players = get_byte(&mut it);
317 let max_players = get_byte(&mut it);
318 let bots = get_byte(&mut it);
319 let server_type = ServerType::from_byte(&get_byte(&mut it));
320 let environment = Platform::from_byte(&get_byte(&mut it));
321 let visibility = Visibility::from_byte(&get_byte(&mut it));
322 let vac = Vac::from_byte(&get_byte(&mut it));
323 let game_version = get_string(&mut it);
324
325 let extra_data_flag: Option<u8>;
326 if let Some(u) = it.next() {
327 extra_data_flag = Some(*u);
328 } else {
329 extra_data_flag = None;
330 }
331
332 let port: Option<Short>;
333 if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x80) != 0
334 {
335 port = Some(get_short(&mut it));
336 } else {
337 port = None;
338 }
339
340 let steam_id: Option<LongLong>;
341 if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x10) != 0
342 {
343 steam_id = Some(get_longlong(&mut it));
344 } else {
345 steam_id = None;
346 }
347
348 let spectator_port: Option<Short>;
349 let spectator_name: Option<String>;
350 if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x40) != 0
351 {
352 spectator_port = Some(get_short(&mut it));
353 spectator_name = Some(get_string(&mut it));
354 } else {
355 spectator_port = None;
356 spectator_name = None;
357 }
358
359 let keywords: Option<String>;
360 if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x20) != 0
361 {
362 keywords = Some(get_string(&mut it));
363 } else {
364 keywords = None;
365 }
366
367 let game_id: Option<LongLong>;
368 if extra_data_flag.is_some() && (extra_data_flag.expect("data exists") & 0x01) != 0
369 {
370 game_id = Some(get_longlong(&mut it));
371 } else {
372 game_id = None;
373 }
374
375 let trailing_bytes: Option<Vec<u8>> = if it.len() > 0 {
377 let mut min_bytes: Vec<u8> = it.into_iter().map(|x| *x).collect();
379 compress_trailing_null_bytes(&mut min_bytes);
380
381 if min_bytes.len() == 1 && *min_bytes.last().expect("last byte exists") == 0 {
383 None
384 } else {
385 Some(min_bytes.into_iter().collect::<Vec<u8>>())
386 }
387 } else {
388 None
389 };
390
391 Self {
392 header,
393 game_id,
394 trailing_bytes,
395 keywords,
396 spectator_port,
397 spectator_name,
398 extra_data_flag,
399 steam_id,
400 protocol,
401 name,
402 map,
403 folder,
404 game,
405 id,
406 players,
407 max_players,
408 bots,
409 server_type,
410 environment,
411 visibility,
412 vac,
413 game_version,
414 port,
415 }
416 }
417 }
418
419 impl Info {
421 pub fn name(&self) -> &str {
423 &self.name
424 }
425 pub fn map(&self) -> &str {
427 &self.map
428 }
429 pub fn folder(&self) -> &str {
431 &self.folder
432 }
433 pub fn keywords(&self) -> &Option<String> {
436 &self.keywords
437 }
438
439 pub fn game(&self) -> &str {
441 &self.game
442 }
443 pub fn game_id(&self) -> &Option<LongLong> {
447 &self.game_id
448 }
449 pub fn game_version(&self) -> &str {
451 &self.game_version
452 }
453 pub fn steam_app_id(&self) -> &Short {
455 &self.id
456 }
457 pub fn steam_id(&self) -> &Option<LongLong> {
459 &self.steam_id
460 }
461
462 pub fn player_count(&self) -> &Byte {
464 &self.players
465 }
466 pub fn player_max(&self) -> &Byte {
468 &self.max_players
469 }
470 pub fn bot_count(&self) -> &Byte {
472 &self.bots
473 }
474
475 pub fn server_type(&self) -> &ServerType {
477 &self.server_type
478 }
479 pub fn platform(&self) -> &Platform {
481 &self.environment
482 }
483
484 pub fn visibility(&self) -> &Visibility {
486 &self.visibility
487 }
488 pub fn vac(&self) -> &Vac {
490 &self.vac
491 }
492
493 pub fn port(&self) -> &Option<Short> {
495 &self.port
496 }
497 pub fn spectator_name(&self) -> &Option<String> {
499 &self.spectator_name
500 }
501 pub fn spectator_port(&self) -> &Option<Short> {
503 &self.spectator_port
504 }
505 }
506
507 #[derive(Debug, Eq, PartialEq, Clone)]
508 pub enum ServerType {
509 Dedicated,
510 NonDedicated,
511 SourceTvRelay,
512 }
513
514 impl ServerType {
515 fn from_byte(byte: &u8) -> Self {
516 use self::ServerType::{Dedicated, NonDedicated, SourceTvRelay};
517
518 match *byte as char {
519 'd' => Dedicated,
520 'l' => NonDedicated,
521 'p' => SourceTvRelay,
522 _ => panic!("Unrecognized Server Type: <{byte}>."),
523 }
524 }
525 }
526
527 #[derive(Debug, Eq, PartialEq, Clone)]
528 pub enum Platform {
529 Linux,
530 Windows,
531 Mac,
532 }
533
534 impl Platform {
535 fn from_byte(byte: &u8) -> Self {
536 use self::Platform::{Linux, Mac, Windows};
537
538 match *byte as char {
539 'l' => Linux,
540 'w' => Windows,
541 'm' => Mac,
542 'o' => Mac,
543 _ => panic!("Unrecognized Environment: <{byte}>."),
544 }
545 }
546 }
547
548 #[derive(Debug, Eq, PartialEq, Clone)]
549 pub enum Visibility {
550 Public,
551 Private,
552 }
553
554 impl Visibility {
555 fn from_byte(byte: &u8) -> Self {
556 use self::Visibility::{Private, Public};
557
558 match *byte {
559 0x00 => Public,
560 0x01 => Private,
561 _ => panic!("Unrecognized Visibility Byte: <{byte}>."),
562 }
563 }
564 }
565
566 #[derive(Debug, Eq, PartialEq, Clone)]
567 pub enum Vac {
569 Unsecured,
570 Secured,
571 }
572
573 impl Vac {
574 fn from_byte(byte: &u8) -> Self {
575 use self::Vac::{Secured, Unsecured};
576
577 match *byte {
578 0x00 => Unsecured,
579 0x01 => Secured,
580 _ => panic!("Unrecognized Vac Byte: <{byte}>."),
581 }
582 }
583 }
584
585 #[cfg(test)]
586 mod tests {
587 use super::*;
588 #[test]
589 fn test_servertype_from_byte() {
590 assert_eq!(ServerType::Dedicated, ServerType::from_byte(&('d' as u8)));
591 }
592 #[test]
593 fn test_environment_from_byte() {
594 assert_eq!(Platform::Linux, Platform::from_byte(&('l' as u8)));
595 }
596 #[test]
597 fn test_visibility_from_byte() {
598 assert_eq!(Visibility::Public, Visibility::from_byte(&(0x00)));
599 }
600 #[test]
601 fn test_vac_from_byte() {
602 assert_eq!(Vac::Secured, Vac::from_byte(&(0x01)));
603 }
604 }
605 }
606}
607
608pub mod server {
609
610 use crate::{MULTI_PACKET_RESPONSE_HEADER, PACKET_SIZE, SIMPLE_RESPONSE_HEADER};
611 use std::collections::HashMap;
612 use std::error::Error;
613 use std::io;
614 use std::net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket};
615 use std::time::Duration;
616
617 use crate::models::info::Info;
618 use crate::models::Player;
619 use crate::types::Byte;
620 use crate::utils::get_multipacket_data;
621
622 pub type Rules = HashMap<String, String>;
623
624 #[derive(Debug)]
634 pub struct Server {
635 socket: UdpSocket,
636 addr: SocketAddr,
637 }
638
639 impl Server {
640 pub fn new(url: &str) -> Result<Self, Box<dyn Error>> {
641 let addr: SocketAddr;
643 let socket: UdpSocket;
644
645 let result: Result<SocketAddr, _> = url.parse();
647 if let Ok(a) = result {
648 addr = a;
649 } else {
650 if let Err(e) = result {
651 return Err(Box::new(e));
652 } else {
653 unreachable!();
654 }
655 }
656
657 let result: Result<UdpSocket, _> =
658 UdpSocket::bind((IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0));
659 if let Ok(s) = result {
660 socket = s;
661 } else {
662 if let Err(e) = result {
663 return Err(Box::new(e));
664 } else {
665 unreachable!();
666 }
667 }
668
669 socket.set_read_timeout(Some(Duration::from_secs(1)))?;
671 socket.set_write_timeout(Some(Duration::from_secs(1)))?;
672
673 Ok(Self { addr, socket })
675 }
676 }
677
678 impl Server {
680 pub fn set_read_timeout(
681 &mut self,
682 duration: Option<Duration>,
683 ) -> Result<(), Box<dyn Error>> {
684 self.socket.set_read_timeout(duration)?;
685 Ok(())
686 }
687 pub fn set_write_timeout(
688 &mut self,
689 duration: Option<Duration>,
690 ) -> Result<(), Box<dyn Error>> {
691 self.socket.set_write_timeout(duration)?;
692 Ok(())
693 }
694 }
695
696 impl Server {
698 pub fn info(&self) -> Result<Info, io::Error> {
699 let mut request: Vec<u8> = vec![
700 255, 255, 255, 255, 84, 83, 111, 117, 114, 99, 101, 32, 69, 110, 103, 105, 110,
701 101, 32, 81, 117, 101, 114, 121, 0,
702 ];
703
704 self.socket.send_to(&request, &self.addr)?;
705
706 let mut buffer = [0; PACKET_SIZE];
707 let mut bytes_returned = self.socket.recv(&mut buffer)?;
708
709 if bytes_returned == 9 {
710 let challenge = buffer
714 .into_iter()
715 .rev()
716 .skip_while(|&i| i == 0)
717 .collect::<Vec<u8>>()
718 .to_owned()
719 .into_iter()
720 .rev()
721 .collect::<Vec<u8>>()[5..]
722 .to_vec();
723
724 request.extend(challenge);
725
726 self.socket.send_to(&request, &self.addr)?;
727 buffer = [0; PACKET_SIZE];
728 bytes_returned = self.socket.recv(&mut buffer)?;
729 }
730
731 let packet_header = &buffer[..4];
732 let payload: Vec<u8>;
733
734 if packet_header == SIMPLE_RESPONSE_HEADER {
735 payload = buffer[4..bytes_returned + 1].to_vec();
736 } else if packet_header == MULTI_PACKET_RESPONSE_HEADER {
737 let (_answer_id, total, packet_id) = get_multipacket_data(&buffer);
740 let mut packet_map: HashMap<Byte, Vec<u8>> = HashMap::with_capacity(total as usize);
741
742 let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
743 packet_map.insert(packet_id, current_payload);
744
745 while total > packet_map.len() as u8 {
747 buffer = [0; PACKET_SIZE]; bytes_returned = self.socket.recv(&mut buffer)?;
749
750 let (_answer_id, _total, packet_id) = get_multipacket_data(&buffer);
751 let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
752 packet_map.insert(packet_id, current_payload);
753 }
754
755 let mut v: Vec<(u8, Vec<u8>)> = packet_map.into_iter().collect();
757 v.sort_by_key(|i| i.0);
758 payload = v
759 .into_iter()
760 .map(|(_, bytes)| bytes)
761 .flatten()
762 .collect::<Vec<u8>>();
763 } else {
764 panic!("An unknown packet header was received.");
765 }
766
767 let info = Info::from_bytes(&payload);
768 Ok(info)
769 }
770 }
771
772 impl Server {
774 pub fn players(&self) -> Result<Vec<Player>, io::Error> {
775 let request = [
776 0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0xFF, ];
780
781 self.socket.send_to(&request, &self.addr)?;
782
783 let mut buffer = [0; PACKET_SIZE];
784 let _bytes_returned = self.socket.recv(&mut buffer)?;
785
786 let challenge = buffer
788 .into_iter()
789 .rev()
790 .skip_while(|&i| i == 0)
791 .collect::<Vec<u8>>()
792 .to_owned()
793 .into_iter()
794 .rev()
795 .collect::<Vec<u8>>()[5..]
796 .to_vec();
797
798 let mut request = vec![
800 0xFF, 0xFF, 0xFF, 0xFF, 0x55, ];
803 request.extend(challenge);
804
805 self.socket.send_to(&request, &self.addr)?;
807 buffer = [0; PACKET_SIZE];
808 let mut bytes_returned = self.socket.recv(&mut buffer)?;
809
810 let packet_header = &buffer[..=3];
812
813 let payload: Vec<u8>;
814 if packet_header == SIMPLE_RESPONSE_HEADER {
815 payload = buffer[4..].to_vec();
816 } else if packet_header == MULTI_PACKET_RESPONSE_HEADER {
817 let (_answer_id, total, packet_id) = get_multipacket_data(&buffer);
820 let mut packet_map: HashMap<Byte, Vec<u8>> = HashMap::with_capacity(total as usize);
821
822 let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
823 packet_map.insert(packet_id, current_payload);
824
825 while total > packet_map.len() as u8 {
827 buffer = [0; PACKET_SIZE]; bytes_returned = self.socket.recv(&mut buffer)?;
829
830 let (_answer_id, _total, packet_id) = get_multipacket_data(&buffer);
831 let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
832 packet_map.insert(packet_id, current_payload);
833 }
834
835 let mut v: Vec<(u8, Vec<u8>)> = packet_map.into_iter().collect();
837 v.sort_by_key(|i| i.0);
838 payload = v
839 .into_iter()
840 .map(|(_, bytes)| bytes)
841 .flatten()
842 .collect::<Vec<u8>>();
843 } else {
844 panic!("An unknown packet header was received.");
845 }
846
847 let _header: &Byte = &payload[0];
848 let player_count: Byte = payload[1].clone();
849
850 let mut it = payload[2..].iter();
851 let mut players: Vec<Player> = Vec::new();
852 for _ in 0..player_count {
853 let player = Player::from_iter_bytes(&mut it);
854 players.push(player);
855 }
856
857 Ok(players)
858 }
859 }
860
861 impl Server {
863 pub fn rules(&self) -> Result<Rules, io::Error> {
864 use crate::utils::compress_trailing_null_bytes;
865
866 let request = [
867 0xFF, 0xFF, 0xFF, 0xFF, 0x56, 0xFF, 0xFF, 0xFF, 0xFF, ];
871
872 self.socket.send_to(&request, &self.addr)?;
873
874 let mut buffer = [0; PACKET_SIZE];
875 let _bytes_returned = self.socket.recv(&mut buffer)?;
876
877 let challenge = buffer
879 .into_iter()
880 .rev()
881 .skip_while(|&i| i == 0)
882 .collect::<Vec<u8>>()
883 .to_owned()
884 .into_iter()
885 .rev()
886 .collect::<Vec<u8>>()[5..]
887 .to_vec();
888
889 let mut request = vec![
891 0xFF, 0xFF, 0xFF, 0xFF, 0x56, ];
894 request.extend(challenge);
895
896 self.socket.send_to(&request, &self.addr)?;
898 buffer = [0; PACKET_SIZE];
899 let mut bytes_returned = self.socket.recv(&mut buffer)?;
900
901 let packet_header = &buffer[..=3];
903 let _header: &Byte = &buffer[4];
904
905 let mut payload: Vec<u8>;
906 if packet_header == SIMPLE_RESPONSE_HEADER {
907 let _rule_count: Byte = buffer[5].clone();
908 let _ = buffer[6]; payload = buffer[7..].to_vec();
910 compress_trailing_null_bytes(&mut payload);
911 } else if packet_header == MULTI_PACKET_RESPONSE_HEADER {
912 let (_answer_id, total, packet_id) = get_multipacket_data(&buffer);
915 let mut packet_map: HashMap<Byte, Vec<u8>> = HashMap::with_capacity(total as usize);
916
917 let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
918 packet_map.insert(packet_id, current_payload);
919
920 while total > packet_map.len() as u8 {
922 buffer = [0; PACKET_SIZE]; bytes_returned = self.socket.recv(&mut buffer)?;
924
925 let (_answer_id, _total, packet_id) = get_multipacket_data(&buffer);
926 let current_payload = buffer[(4 + 4 + 1 + 1)..bytes_returned + 1].to_vec();
927 packet_map.insert(packet_id, current_payload);
928 }
929
930 let mut v: Vec<(u8, Vec<u8>)> = packet_map.into_iter().collect();
932 v.sort_by_key(|i| i.0);
933 payload = v
934 .into_iter()
935 .map(|(_, bytes)| bytes)
936 .flatten()
937 .collect::<Vec<u8>>();
938 } else {
939 panic!("An unknown packet header was received.");
940 }
941
942 let rules: Rules = Self::get_rules(&payload);
943
944 Ok(rules)
945 }
946
947 pub fn get_rules(bytes: &[u8]) -> Rules {
948 use crate::types::get_string;
949
950 let mut it = bytes.iter();
951 let mut rules = HashMap::new();
952
953 while it.len() > 0 {
954 let name = get_string(&mut it);
955 let value = get_string(&mut it);
956
957 rules.insert(name, value);
958 }
959
960 rules
961 }
962 }
963
964 #[cfg(test)]
965 mod tests {
966
967 use super::*;
968
969 #[test]
970 fn test_client_init() {
971 let server: Result<_, _> = Server::new("");
972 if let Err(_) = server {
973 } else {
974 assert!(false, "Server was successfully contructed when it should have failed when parsing URL.")
975 }
976 }
977
978 #[test]
979 #[ignore]
980 fn test_client_init_live() {
981 let server: Result<_, _> = Server::new("54.186.150.6:9879");
983 if let Ok(_) = server {
984 } else {
985 assert!(
986 false,
987 "Server failed to be contructed when it should have succeeded (LIVE TEST)."
988 )
989 }
990 }
991
992 #[test]
993 fn test_client_info() {
994 let server = Server::new("127.0.0.1:12345").unwrap();
996 let info: Result<Info, _> = server.info();
997 if let Err(_) = info {
998 } else {
999 assert!(
1000 false,
1001 "Target URL is not real, but we got back an Ok response for A2S_INFO."
1002 )
1003 }
1004 }
1005
1006 #[test]
1007 #[ignore]
1008 fn test_client_info_live() {
1009 let server = Server::new("54.186.150.6:9879").unwrap();
1011 let info: Result<Info, _> = server.info();
1012 if let Ok(_) = info {
1013 } else {
1014 assert!(
1015 false,
1016 "Target URL is real and live, but we got back an Err response for A2S_INFO."
1017 )
1018 }
1019 }
1020 #[test]
1021 #[ignore]
1022 fn test_client_players_live() {
1023 let server = Server::new("54.186.150.6:9879").unwrap();
1025 let players: Result<Vec<Player>, _> = server.players();
1026 if let Ok(_) = players {
1027 } else {
1028 assert!(
1029 false,
1030 "Target URL is real and live, but we got back an Err response for A2S_PLAYER."
1031 )
1032 }
1033 }
1034 #[test]
1035 #[ignore]
1036 fn test_client_rules_live() {
1037 let server = Server::new("54.186.150.6:9879").unwrap();
1039 let rules: Result<Rules, _> = server.rules();
1040 if let Ok(_) = rules {
1041 } else {
1042 assert!(
1043 false,
1044 "Target URL is real and live, but we got back an Err response for A2S_RULES."
1045 )
1046 }
1047 }
1048 }
1049}
1050
1051pub mod utils {
1052 use crate::types::{get_byte, get_long, Byte, Long};
1053
1054 pub fn get_multipacket_data(buffer: &[u8]) -> (Long, Byte, Byte) {
1055 let v = buffer.to_vec();
1056 let mut buffer_mut = v.iter();
1057
1058 let _header = get_long(&mut buffer_mut);
1059 let answer_id = get_long(&mut buffer_mut);
1060 let total = get_byte(&mut buffer_mut);
1061 let packet_id = get_byte(&mut buffer_mut);
1062
1063 (answer_id, total, packet_id)
1064 }
1065
1066 pub fn compress_trailing_null_bytes(bytes: &mut Vec<u8>) {
1067 if bytes.len() == 0 || bytes.len() == 1 {
1069 return;
1070 }
1071 if bytes.last().expect("a last byte exists") != &0 {
1073 return;
1074 }
1075
1076 let mut last = bytes.pop().expect("the next byte exists");
1078 while last == 0 && bytes.len() > 0 {
1079 last = bytes.pop().expect("the next byte exists");
1080 }
1081 bytes.push(last);
1082 bytes.push(0x00);
1083 }
1084
1085 #[cfg(test)]
1086 mod tests {
1087
1088 use super::*;
1089
1090 #[test]
1091 fn test_compress_null_bytes_basic() {
1092 let mut bytes: Vec<u8> = vec![1, 2, 3, 0, 0, 0, 0];
1093 compress_trailing_null_bytes(&mut bytes);
1094
1095 let result = bytes;
1096 let expected: Vec<u8> = vec![1, 2, 3, 0];
1097
1098 assert_eq!(result, expected);
1099 }
1100 #[test]
1101 fn test_compress_null_bytes_with_no_trailing_zeroes() {
1102 let mut bytes: Vec<u8> = vec![1, 2, 3];
1103 compress_trailing_null_bytes(&mut bytes);
1104
1105 let result = bytes;
1106 let expected: Vec<u8> = vec![1, 2, 3];
1107
1108 assert_eq!(result, expected);
1109 }
1110 #[test]
1111 fn test_compress_null_bytes_with_one_trailing_zeroes() {
1112 let mut bytes: Vec<u8> = vec![1, 2, 3, 0];
1113 compress_trailing_null_bytes(&mut bytes);
1114
1115 let result = bytes;
1116 let expected: Vec<u8> = vec![1, 2, 3, 0];
1117
1118 assert_eq!(result, expected);
1119 }
1120 #[test]
1121 fn test_compress_null_bytes_with_empty_vector() {
1122 let mut bytes: Vec<u8> = vec![];
1123 compress_trailing_null_bytes(&mut bytes);
1124
1125 let result = bytes;
1126 let expected: Vec<u8> = vec![];
1127
1128 assert_eq!(result, expected);
1129 }
1130 #[test]
1131 fn test_compress_null_bytes_with_one_zero_as_vector() {
1132 let mut bytes: Vec<u8> = vec![0];
1133 compress_trailing_null_bytes(&mut bytes);
1134
1135 let result = bytes;
1136 let expected: Vec<u8> = vec![0];
1137
1138 assert_eq!(result, expected);
1139 }
1140 }
1141}