diff --git a/Cargo.toml b/Cargo.toml index 557478a..0b5c3e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ homepage = "https://github.com/CosminPerRam/rust-gamedig" documentation = "https://docs.rs/gamedig/latest/gamedig/" repository = "https://github.com/CosminPerRam/rust-gamedig" readme = "README.md" -keywords = ["server", "valve", "games", "checker", "status"] +keywords = ["server", "verify", "game", "check", "status"] [package.metadata] msrv = "1.58.1" diff --git a/README.md b/README.md index 1b2a48b..a419e4f 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,10 @@ MSRV is `1.58.1` and the code is cross-platform. # Example Basic usage of the library is: ```rust -use gamedig::TF2; +use gamedig::games::tf2; fn main() { - let response = TF2::query("91.216.250.10", None); - //query your favorite game/protocol/service, some might come with different parameters - //here its just the IP and the port (if None, its gonna be the default from the protocol) - + let response = tf2::query("91.216.250.10", None); //or Some(27015), None is the default protocol port match response { Err(error) => println!("Couldn't query, error: {error}"), Ok(r) => println!("{:?}", r) @@ -29,4 +26,4 @@ Curious about the history and what changed between versions? you can see just th To see the supported (or the planned to support) games, see [GAMES](GAMES.md). # Contributing -If you want see your favorite game/service being supported here, open an issue (or do a pull request if you want to implement it yourself)! +If you want see your favorite game/service being supported here, open an issue and I'll prioritize it! (or do a pull request if you want to implement it yourself) diff --git a/examples/csgo.rs b/examples/csgo.rs index 0b20adb..48f0943 100644 --- a/examples/csgo.rs +++ b/examples/csgo.rs @@ -1,8 +1,8 @@ -use gamedig::CSGO; +use gamedig::games::csgo; fn main() { - let response = CSGO::query("51.38.142.109", None); + let response = csgo::query("51.38.142.109", None); match response { Err(error) => println!("Couldn't query, error: {error}"), Ok(r) => println!("{:?}", r) diff --git a/examples/tf2.rs b/examples/tf2.rs index e77a699..f0fc2ec 100644 --- a/examples/tf2.rs +++ b/examples/tf2.rs @@ -1,8 +1,8 @@ -use gamedig::TF2; +use gamedig::games::tf2; fn main() { - let response = TF2::query("91.216.250.10", None); + let response = tf2::query("91.216.250.10", None); //or Some(27015), None is the default protocol port match response { Err(error) => println!("Couldn't query, error: {error}"), Ok(r) => println!("{:?}", r) diff --git a/examples/the_ship.rs b/examples/the_ship.rs index 496fc6f..14524e1 100644 --- a/examples/the_ship.rs +++ b/examples/the_ship.rs @@ -1,8 +1,8 @@ -use gamedig::TheShip; +use gamedig::games::the_ship; fn main() { - let response = TheShip::query("46.4.48.226", Some(27017)); + let response = the_ship::query("46.4.48.226", Some(27017)); match response { Err(error) => println!("Couldn't query, error: {error}"), Ok(r) => println!("{:?}", r) diff --git a/src/errors.rs b/src/errors.rs index 657b163..6e2210f 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,14 +1,22 @@ use core::fmt; use std::fmt::Formatter; +/// GameDigError, every error you can encounter using the library. #[derive(Debug, Clone)] pub enum GDError { + /// The received packet was bigger than the buffer size. PacketOverflow(String), + /// The received packet was shorter than the expected one. PacketUnderflow(String), + /// The received packet was badly formatted. PacketBad(String), + /// Couldn't send the packet. PacketSend(String), + /// Couldn't send the receive. PacketReceive(String), + /// Unknown cast while translating a value to an enum UnknownEnumCast, + /// The server queried is not from the queried game. BadGame(String) } diff --git a/src/games/csgo.rs b/src/games/csgo.rs index b99fdb6..cc45ab4 100644 --- a/src/games/csgo.rs +++ b/src/games/csgo.rs @@ -1,16 +1,12 @@ use crate::errors::GDError; use crate::valve::{ValveProtocol, App, GatheringSettings, Response}; -pub struct CSGO; - -impl CSGO { - pub fn query(address: &str, port: Option) -> Result { - ValveProtocol::query(App::CSGO, address, match port { - None => 27015, - Some(port) => port - }, GatheringSettings { - players: true, - rules: true - }) - } +pub fn query(address: &str, port: Option) -> Result { + ValveProtocol::query(App::CSGO, address, match port { + None => 27015, + Some(port) => port + }, GatheringSettings { + players: true, + rules: true + }) } diff --git a/src/games/mod.rs b/src/games/mod.rs index e6cb505..a0f3e63 100644 --- a/src/games/mod.rs +++ b/src/games/mod.rs @@ -1,8 +1,6 @@ +//! Currently supported games. + pub mod tf2; pub mod the_ship; pub mod csgo; - -pub use tf2::*; -pub use the_ship::*; -pub use csgo::*; diff --git a/src/games/tf2.rs b/src/games/tf2.rs index 4f39798..dcee6fb 100644 --- a/src/games/tf2.rs +++ b/src/games/tf2.rs @@ -1,16 +1,12 @@ use crate::errors::GDError; use crate::valve::{ValveProtocol, App, GatheringSettings, Response}; -pub struct TF2; - -impl TF2 { - pub fn query(address: &str, port: Option) -> Result { - ValveProtocol::query(App::TF2, address, match port { - None => 27015, - Some(port) => port - }, GatheringSettings { - players: true, - rules: true - }) - } +pub fn query(address: &str, port: Option) -> Result { + ValveProtocol::query(App::TF2, address, match port { + None => 27015, + Some(port) => port + }, GatheringSettings { + players: true, + rules: true + }) } diff --git a/src/games/the_ship.rs b/src/games/the_ship.rs index ae86d92..a9d1fba 100644 --- a/src/games/the_ship.rs +++ b/src/games/the_ship.rs @@ -1,16 +1,12 @@ use crate::errors::GDError; use crate::valve::{ValveProtocol, App, GatheringSettings, Response}; -pub struct TheShip; - -impl TheShip { - pub fn query(address: &str, port: Option) -> Result { - ValveProtocol::query(App::TheShip, address, match port { - None => 27015, - Some(port) => port - }, GatheringSettings { - players: true, - rules: true - }) - } +pub fn query(address: &str, port: Option) -> Result { + ValveProtocol::query(App::TheShip, address, match port { + None => 27015, + Some(port) => port + }, GatheringSettings { + players: true, + rules: true + }) } diff --git a/src/lib.rs b/src/lib.rs index 59232a6..56c1905 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,24 @@ +//! Query many servers +//! +//! # Example +//! +//! ```no_run +//! use gamedig::games::tf2; +//! +//! fn main() { +//! let response = tf2::query("91.216.250.10", None); //or Some(27015), None is the default protocol port +//! match response { +//! Err(error) => println!("Couldn't query, error: {error}"), +//! Ok(r) => println!("{:?}", r) +//! } +//! } +//! ``` + pub mod errors; pub mod protocols; -mod utils; pub mod games; +mod utils; pub use errors::*; pub use protocols::*; diff --git a/src/protocols/mod.rs b/src/protocols/mod.rs index 3deed53..f84b187 100644 --- a/src/protocols/mod.rs +++ b/src/protocols/mod.rs @@ -1,2 +1,8 @@ +//! Protocols that are currently implemented. +//! +//! A protocol will be here if it supports multiple entries, if not, its implementation will be +//! in that specific needed place, a protocol can be independently queried. + +/// Reference: [Server Query](https://developer.valvesoftware.com/wiki/Server_queries) pub mod valve; diff --git a/src/protocols/valve.rs b/src/protocols/valve.rs index 2308f9c..0949d9a 100644 --- a/src/protocols/valve.rs +++ b/src/protocols/valve.rs @@ -3,6 +3,7 @@ use std::net::UdpSocket; use crate::errors::GDError; use crate::utils::{buffer, complete_address, concat_u8_arrays}; +/// The type of the server. #[derive(Debug)] pub enum Server { Dedicated, @@ -10,6 +11,7 @@ pub enum Server { SourceTV } +/// The Operating System that the server is on. #[derive(Debug)] pub enum Environment { Linux, @@ -17,6 +19,7 @@ pub enum Environment { Mac } +/// A query response. #[derive(Debug)] pub struct Response { pub info: ServerInfo, @@ -24,47 +27,73 @@ pub struct Response { pub rules: Option } +/// General server information's. #[derive(Debug)] pub struct ServerInfo { + /// Protocol used by the server. pub protocol: u8, - pub map: String, + /// Name of the server. pub name: String, + /// Map name. + pub map: String, + /// Name of the folder containing the game files. pub folder: String, + /// Full name of the game. pub game: String, + /// [Steam Application ID](https://developer.valvesoftware.com/wiki/Steam_Application_ID) of game. pub id: u16, + /// Number of players on the server. pub players: u8, + /// Maximum number of players the server reports it can hold. pub max_players: u8, + /// Number of bots on the server. pub bots: u8, + /// Dedicated, NonDedicated or SourceTV pub server_type: Server, + /// The Operating System that the server is on. pub environment_type: Environment, + /// Indicated whether the server requires a password. pub has_password: bool, + /// Indicated whether the server uses VAC. pub vac_secured: bool, + /// [The ship](https://developer.valvesoftware.com/wiki/The_Ship) extra data pub the_ship: Option, + /// Version of the game installed on the server. pub version: String, + /// Some extra data that the server might provide or not. pub extra_data: Option } +/// Server's players. #[derive(Debug)] pub struct ServerPlayers { pub count: u8, pub players: Vec } +/// Data about a player #[derive(Debug)] pub struct Player { + /// Player's name. pub name: String, + /// General score. pub score: u32, + /// How long they've been on the server for. pub duration: f32, + /// Only for [the ship](https://developer.valvesoftware.com/wiki/The_Ship): deaths count pub deaths: Option, //the_ship + /// Only for [the ship](https://developer.valvesoftware.com/wiki/The_Ship): money amount pub money: Option, //the_ship } +/// Server's rules. #[derive(Debug)] pub struct ServerRules { pub count: u16, pub map: HashMap } +/// Only present for [the ship](https://developer.valvesoftware.com/wiki/The_Ship). #[derive(Debug)] pub struct TheShip { pub mode: u8, @@ -72,23 +101,35 @@ pub struct TheShip { pub duration: u8 } +/// Some extra data that the server might provide or not. #[derive(Debug)] pub struct ExtraData { + /// The server's game port number. pub port: Option, + /// Server's SteamID. pub steam_id: Option, + /// Spectator port number for SourceTV. pub tv_port: Option, + /// Name of the spectator server for SourceTV. pub tv_name: Option, + /// Tags that describe the game according to the server. pub keywords: Option, + /// The server's 64-bit GameID. pub game_id: Option } +/// The type of the request, see the [protocol](https://developer.valvesoftware.com/wiki/Server_queries). #[derive(PartialEq)] pub enum Request { + /// Known as `A2S_INFO` INFO, + /// Known as `A2S_PLAYERS` PLAYERS, + /// Known as `A2S_RULES` RULES } +/// Supported app id's #[derive(PartialEq)] pub enum App { TF2 = 440, @@ -109,6 +150,7 @@ impl TryFrom for App { } } +/// What data to gather, purely used only with the query function. pub struct GatheringSettings { pub players: bool, pub rules: bool @@ -152,6 +194,7 @@ impl ValveProtocol { Ok(final_packet) } + /// Ask for a specific request only. pub fn get_request_data(&self, app: &App, kind: Request) -> Result, GDError> { let info_initial_packet = vec![0xFF, 0xFF, 0xFF, 0xFF, 0x54, 0x53, 0x6F, 0x75, 0x72, 0x63, 0x65, 0x20, 0x45, 0x6E, 0x67, 0x69, 0x6E, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00]; let players_initial_packet = vec![0xFF, 0xFF, 0xFF, 0xFF, 0x55, 0xFF, 0xFF, 0xFF, 0xFF]; @@ -191,7 +234,8 @@ impl ValveProtocol { } } - fn get_server_info(&self, app: &App) -> Result { + /// Get the server information's. + pub fn get_server_info(&self, app: &App) -> Result { let buf = self.get_request_data(app, Request::INFO)?; let mut pos = 0; @@ -260,7 +304,8 @@ impl ValveProtocol { }) } - fn get_server_players(&self, app: &App) -> Result { + /// Get the server player's. + pub fn get_server_players(&self, app: &App) -> Result { let buf = self.get_request_data(app, Request::PLAYERS)?; let mut pos = 0; @@ -290,7 +335,8 @@ impl ValveProtocol { }) } - fn get_server_rules(&self, app: &App) -> Result, GDError> { + /// Get the server rules's. + pub fn get_server_rules(&self, app: &App) -> Result, GDError> { if *app == App::CSGO { //cause csgo response here is broken after feb 21 2014 return Ok(None); }