mirror of
https://github.com/tribufu/rust-gamedig
synced 2026-06-01 09:42:41 +00:00
feat(protocols): Add more control over gathering additional information (#180)
* protocols: Add more control over gathering additional information Adds GatherToggle which allows choosing the behaviour for how the query handles fetching additional information. The choices are: - DontGather - Don't attempt to fetch information - AttemptGather - Try to fetch the information but ignore errors - Required - Try to fetch information and fail if it errors A handy macro was also added to utils to dispatch additional queries based on a GatherToggle value. * Add/Update badge * protocols: Improve GatherToggle enum names Co-Authored-By: Cain <75994858+cainthebest@users.noreply.github.com> Co-Authored-By: CosminPerRam <cosmin.p@live.com> * Add/Update badge --------- Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Cain <75994858+cainthebest@users.noreply.github.com> Co-authored-by: CosminPerRam <cosmin.p@live.com>
This commit is contained in:
parent
6d0c25d6ea
commit
89ed19f089
10 changed files with 195 additions and 64 deletions
|
|
@ -319,14 +319,16 @@ pub struct ExtraRequestSettings {
|
|||
///
|
||||
/// Used by:
|
||||
/// - [valve::GatheringSettings#structfield.players]
|
||||
/// - [unreal2::GatheringSettings#structfield.players]
|
||||
#[cfg_attr(feature = "clap", arg(long))]
|
||||
pub gather_players: Option<bool>,
|
||||
pub gather_players: Option<GatherToggle>,
|
||||
/// Whether to gather rule information.
|
||||
///
|
||||
/// Used by:
|
||||
/// - [valve::GatheringSettings#structfield.rules]
|
||||
/// - [unreal2::GatheringSettings#structfield.mutators_and_rules]
|
||||
#[cfg_attr(feature = "clap", arg(long))]
|
||||
pub gather_rules: Option<bool>,
|
||||
pub gather_rules: Option<GatherToggle>,
|
||||
/// Whether to check if the App ID is valid.
|
||||
///
|
||||
/// Used by:
|
||||
|
|
@ -335,6 +337,31 @@ pub struct ExtraRequestSettings {
|
|||
pub check_app_id: Option<bool>,
|
||||
}
|
||||
|
||||
/// Select how to go about gathering extra information via additional requests.
|
||||
///
|
||||
/// Used by:
|
||||
/// - [ExtraRequestSettings]
|
||||
/// - [valve::GatheringSettings]
|
||||
/// - [unreal2::GatheringSettings]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "clap", derive(clap::ValueEnum))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
|
||||
pub enum GatherToggle {
|
||||
/// No request is sent for the relevant data. This option bypasses data
|
||||
/// gathering.
|
||||
#[default]
|
||||
Skip,
|
||||
|
||||
/// A request will be sent, but errors are not treated as criticial.
|
||||
/// In the case of an error, the operation will return a default value or
|
||||
/// `None`.
|
||||
Try,
|
||||
|
||||
/// A request will be sent, and any resulting errors will be propagated.
|
||||
/// This option treats successful data gathering as mandatory.
|
||||
Enforce,
|
||||
}
|
||||
|
||||
impl ExtraRequestSettings {
|
||||
/// [Sets hostname](ExtraRequestSettings#structfield.hostname)
|
||||
pub fn set_hostname(mut self, hostname: String) -> Self {
|
||||
|
|
@ -348,12 +375,12 @@ impl ExtraRequestSettings {
|
|||
self
|
||||
}
|
||||
/// [Sets gather players](ExtraRequestSettings#structfield.gather_players)
|
||||
pub const fn set_gather_players(mut self, gather_players: bool) -> Self {
|
||||
pub const fn set_gather_players(mut self, gather_players: GatherToggle) -> Self {
|
||||
self.gather_players = Some(gather_players);
|
||||
self
|
||||
}
|
||||
/// [Sets gather rules](ExtraRequestSettings#structfield.gather_rules)
|
||||
pub const fn set_gather_rules(mut self, gather_rules: bool) -> Self {
|
||||
pub const fn set_gather_rules(mut self, gather_rules: GatherToggle) -> Self {
|
||||
self.gather_rules = Some(gather_rules);
|
||||
self
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::buffer::{Buffer, StringDecoder};
|
|||
use crate::errors::GDErrorKind::PacketBad;
|
||||
use crate::protocols::types::TimeoutSettings;
|
||||
use crate::socket::{Socket, UdpSocket};
|
||||
use crate::utils::retry_on_timeout;
|
||||
use crate::utils::{maybe_gather, retry_on_timeout};
|
||||
use crate::GDResult;
|
||||
|
||||
use super::{GatheringSettings, MutatorsAndRules, PacketKind, Players, Response, ServerInfo};
|
||||
|
|
@ -168,24 +168,22 @@ impl Unreal2Protocol {
|
|||
// Fetch the server info, this can only handle one response packet
|
||||
let mut server_info = self.query_server_info()?;
|
||||
|
||||
let mutators_and_rules = if gather_settings.mutators_and_rules {
|
||||
let response = self.query_mutators_and_rules()?;
|
||||
let mutators_and_rules = maybe_gather!(
|
||||
gather_settings.mutators_and_rules,
|
||||
self.query_mutators_and_rules()
|
||||
)
|
||||
.unwrap_or_default();
|
||||
|
||||
if let Some(password) = response.rules.get("GamePassword") {
|
||||
let string = password.concat().to_lowercase();
|
||||
server_info.password = string == "true";
|
||||
}
|
||||
if let Some(password) = mutators_and_rules.rules.get("GamePassword") {
|
||||
let string = password.concat().to_lowercase();
|
||||
server_info.password = string == "true";
|
||||
}
|
||||
|
||||
response
|
||||
} else {
|
||||
MutatorsAndRules::default()
|
||||
};
|
||||
|
||||
let players = if gather_settings.players {
|
||||
self.query_players(Some(&server_info))?
|
||||
} else {
|
||||
Players::with_capacity(0)
|
||||
};
|
||||
let players = maybe_gather!(
|
||||
gather_settings.players,
|
||||
self.query_players(Some(&server_info))
|
||||
)
|
||||
.unwrap_or_else(|| Players::with_capacity(0));
|
||||
|
||||
// TODO: Handle extra info parsing when we detect certain game types (or maybe
|
||||
// include that in gather settings).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use crate::buffer::Buffer;
|
||||
use crate::errors::GDErrorKind::PacketBad;
|
||||
use crate::protocols::types::{CommonPlayer, CommonResponse, ExtraRequestSettings, GenericPlayer};
|
||||
use crate::protocols::types::{CommonPlayer, CommonResponse, ExtraRequestSettings, GatherToggle, GenericPlayer};
|
||||
use crate::protocols::GenericResponse;
|
||||
use crate::{GDError, GDResult};
|
||||
|
||||
|
|
@ -209,16 +209,16 @@ impl CommonResponse for Response {
|
|||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct GatheringSettings {
|
||||
pub players: bool,
|
||||
pub mutators_and_rules: bool,
|
||||
pub players: GatherToggle,
|
||||
pub mutators_and_rules: GatherToggle,
|
||||
}
|
||||
|
||||
impl GatheringSettings {
|
||||
/// Default values are true for both the players and the rules.
|
||||
/// Default values is attempt both players and rules.
|
||||
pub const fn default() -> Self {
|
||||
Self {
|
||||
players: true,
|
||||
mutators_and_rules: true,
|
||||
players: GatherToggle::Try,
|
||||
mutators_and_rules: GatherToggle::Enforce,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,11 @@ macro_rules! game_query_mod {
|
|||
($mod_name: ident, $pretty_name: expr, $engine: expr, $default_port: literal, $gathering_settings: expr) => {
|
||||
#[doc = $pretty_name]
|
||||
pub mod $mod_name {
|
||||
use crate::protocols::valve::{Engine, GatheringSettings};
|
||||
#[allow(unused_imports)]
|
||||
use crate::protocols::{
|
||||
types::GatherToggle,
|
||||
valve::{Engine, GatheringSettings},
|
||||
};
|
||||
|
||||
crate::protocols::valve::game_query_fn!($pretty_name, $engine, $default_port, $gathering_settings);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
},
|
||||
},
|
||||
socket::{Socket, UdpSocket},
|
||||
utils::{retry_on_timeout, u8_lower_upper},
|
||||
utils::{maybe_gather, retry_on_timeout, u8_lower_upper},
|
||||
GDErrorKind::{BadGame, Decompress, UnknownEnumCast},
|
||||
GDResult,
|
||||
};
|
||||
|
|
@ -470,13 +470,13 @@ fn get_response(
|
|||
|
||||
Ok(Response {
|
||||
info,
|
||||
players: match gather_settings.players {
|
||||
false => None,
|
||||
true => Some(client.get_server_players(&engine, protocol)?),
|
||||
},
|
||||
rules: match gather_settings.rules {
|
||||
false => None,
|
||||
true => Some(client.get_server_rules(&engine, protocol)?),
|
||||
},
|
||||
players: maybe_gather!(
|
||||
gather_settings.players,
|
||||
client.get_server_players(&engine, protocol)
|
||||
),
|
||||
rules: maybe_gather!(
|
||||
gather_settings.rules,
|
||||
client.get_server_rules(&engine, protocol)
|
||||
),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use crate::protocols::types::{CommonPlayer, CommonResponse, ExtraRequestSettings, GenericPlayer};
|
||||
use crate::protocols::types::{CommonPlayer, CommonResponse, ExtraRequestSettings, GatherToggle, GenericPlayer};
|
||||
use crate::GDErrorKind::UnknownEnumCast;
|
||||
use crate::GDResult;
|
||||
use crate::{buffer::Buffer, protocols::GenericResponse};
|
||||
|
|
@ -283,17 +283,18 @@ impl Engine {
|
|||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct GatheringSettings {
|
||||
pub players: bool,
|
||||
pub rules: bool,
|
||||
pub players: GatherToggle,
|
||||
pub rules: GatherToggle,
|
||||
pub check_app_id: bool,
|
||||
}
|
||||
|
||||
impl GatheringSettings {
|
||||
/// Default values are true for both the players and the rules.
|
||||
/// Default values are try to gather but don't fail on timeout for both
|
||||
/// players and rules.
|
||||
pub const fn default() -> Self {
|
||||
Self {
|
||||
players: true,
|
||||
rules: true,
|
||||
players: GatherToggle::Try,
|
||||
rules: GatherToggle::Try,
|
||||
check_app_id: true,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue