|
|
|
@ -8,35 +8,31 @@ use log::{debug, log_enabled, Level};
@@ -8,35 +8,31 @@ use log::{debug, log_enabled, Level};
|
|
|
|
|
|
|
|
|
|
use crate::parser::{Error as ParserError, ParseValue, Parser}; |
|
|
|
|
use crate::server::Server; |
|
|
|
|
use crate::server_info::{Os, ServerFlags, ServerInfo, ServerType}; |
|
|
|
|
use crate::server_info::{ServerFlags, ServerInfo, ServerType}; |
|
|
|
|
|
|
|
|
|
bitflags! { |
|
|
|
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)] |
|
|
|
|
pub struct FilterFlags: u16 { |
|
|
|
|
/// Servers running dedicated
|
|
|
|
|
const DEDICATED = 1 << 0; |
|
|
|
|
/// Servers that are spectator proxies
|
|
|
|
|
const PROXY = 1 << 1; |
|
|
|
|
/// Servers using anti-cheat technology (VAC, but potentially others as well)
|
|
|
|
|
const SECURE = 1 << 2; |
|
|
|
|
/// Servers running on a Linux platform
|
|
|
|
|
const LINUX = 1 << 3; |
|
|
|
|
const SECURE = 1 << 1; |
|
|
|
|
/// Servers that are not password protected
|
|
|
|
|
const PASSWORD = 1 << 4; |
|
|
|
|
const PASSWORD = 1 << 2; |
|
|
|
|
/// Servers that are not empty
|
|
|
|
|
const NOT_EMPTY = 1 << 5; |
|
|
|
|
const NOT_EMPTY = 1 << 3; |
|
|
|
|
/// Servers that are not full
|
|
|
|
|
const FULL = 1 << 6; |
|
|
|
|
const FULL = 1 << 4; |
|
|
|
|
/// Servers that are empty
|
|
|
|
|
const NOPLAYERS = 1 << 7; |
|
|
|
|
const NOPLAYERS = 1 << 5; |
|
|
|
|
/// Servers that are whitelisted
|
|
|
|
|
const WHITE = 1 << 8; |
|
|
|
|
const WHITE = 1 << 6; |
|
|
|
|
/// Servers that are behind NAT
|
|
|
|
|
const NAT = 1 << 9; |
|
|
|
|
const NAT = 1 << 7; |
|
|
|
|
/// Servers that are LAN
|
|
|
|
|
const LAN = 1 << 11; |
|
|
|
|
const LAN = 1 << 8; |
|
|
|
|
/// Servers that has bots
|
|
|
|
|
const BOTS = 1 << 12; |
|
|
|
|
const BOTS = 1 << 9; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -45,9 +41,7 @@ impl<T> From<&ServerInfo<T>> for FilterFlags {
@@ -45,9 +41,7 @@ impl<T> From<&ServerInfo<T>> for FilterFlags {
|
|
|
|
|
let mut flags = Self::empty(); |
|
|
|
|
|
|
|
|
|
flags.set(Self::DEDICATED, info.server_type == ServerType::Dedicated); |
|
|
|
|
flags.set(Self::PROXY, info.server_type == ServerType::Proxy); |
|
|
|
|
flags.set(Self::SECURE, info.flags.contains(ServerFlags::SECURE)); |
|
|
|
|
flags.set(Self::LINUX, info.os == Os::Linux); |
|
|
|
|
flags.set(Self::PASSWORD, info.flags.contains(ServerFlags::PASSWORD)); |
|
|
|
|
flags.set(Self::NOT_EMPTY, info.players > 0); // XXX: and not full?
|
|
|
|
|
flags.set(Self::FULL, info.players >= info.max); |
|
|
|
@ -70,24 +64,12 @@ pub struct Filter<'a> {
@@ -70,24 +64,12 @@ pub struct Filter<'a> {
|
|
|
|
|
pub gamedir: Option<&'a str>, |
|
|
|
|
/// Servers running the specified map (ex. cs_italy)
|
|
|
|
|
pub map: Option<&'a str>, |
|
|
|
|
/// Servers with all of the given tag(s) in sv_tags
|
|
|
|
|
pub gametype: Option<&'a str>, |
|
|
|
|
/// Servers with all of the given tag(s) in their 'hidden' tags (L4D2)
|
|
|
|
|
pub gamedata: Option<&'a str>, |
|
|
|
|
/// Servers with any of the given tag(s) in their 'hidden' tags (L4D2)
|
|
|
|
|
pub gamedataor: Option<&'a str>, |
|
|
|
|
/// Servers with their hostname matching [hostname] (can use * as a wildcard)
|
|
|
|
|
pub name_match: Option<&'a str>, |
|
|
|
|
/// Servers running version [version] (can use * as a wildcard)
|
|
|
|
|
pub version_match: Option<&'a str>, |
|
|
|
|
/// Return only servers on the specified IP address (port supported and optional)
|
|
|
|
|
pub gameaddr: Option<SocketAddrV4>, |
|
|
|
|
/// Servers that are running game [appid]
|
|
|
|
|
pub appid: Option<u32>, |
|
|
|
|
/// Servers that are NOT running game [appid] (This was introduced to block Left 4 Dead games from the Steam Server Browser)
|
|
|
|
|
pub napp: Option<u32>, |
|
|
|
|
/// Return only one server for each unique IP address matched
|
|
|
|
|
pub collapse_addr_hash: bool, |
|
|
|
|
/// Client version.
|
|
|
|
|
pub clver: Option<&'a str>, |
|
|
|
|
|
|
|
|
@ -154,19 +136,11 @@ impl<'a> ParseValue<'a> for Filter<'a> {
@@ -154,19 +136,11 @@ impl<'a> ParseValue<'a> for Filter<'a> {
|
|
|
|
|
b"map" => filter.map = Some(p.parse()?), |
|
|
|
|
b"empty" => filter.insert_flag(FilterFlags::NOT_EMPTY, p.parse()?), |
|
|
|
|
b"full" => filter.insert_flag(FilterFlags::FULL, p.parse()?), |
|
|
|
|
b"linux" => filter.insert_flag(FilterFlags::LINUX, p.parse()?), |
|
|
|
|
b"password" => filter.insert_flag(FilterFlags::PASSWORD, p.parse()?), |
|
|
|
|
b"proxy" => filter.insert_flag(FilterFlags::PROXY, p.parse()?), |
|
|
|
|
b"appid" => filter.appid = Some(p.parse()?), |
|
|
|
|
b"napp" => filter.napp = Some(p.parse()?), |
|
|
|
|
b"noplayers" => filter.insert_flag(FilterFlags::NOPLAYERS, p.parse()?), |
|
|
|
|
b"white" => filter.insert_flag(FilterFlags::WHITE, p.parse()?), |
|
|
|
|
b"gametype" => filter.gametype = Some(p.parse()?), |
|
|
|
|
b"gamedata" => filter.gamedata = Some(p.parse()?), |
|
|
|
|
b"gamedataor" => filter.gamedataor = Some(p.parse()?), |
|
|
|
|
b"name_match" => filter.name_match = Some(p.parse()?), |
|
|
|
|
b"version_match" => filter.version_match = Some(p.parse()?), |
|
|
|
|
b"collapse_addr_hash" => filter.collapse_addr_hash = p.parse()?, |
|
|
|
|
b"gameaddr" => { |
|
|
|
|
let s = p.parse::<&str>()?; |
|
|
|
|
if let Ok(addr) = s.parse() { |
|
|
|
@ -235,31 +209,6 @@ mod tests {
@@ -235,31 +209,6 @@ mod tests {
|
|
|
|
|
map: Some("crossfire"), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_appid { |
|
|
|
|
b"\\appid\\70" => { |
|
|
|
|
appid: Some(70), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_napp { |
|
|
|
|
b"\\napp\\70" => { |
|
|
|
|
napp: Some(70), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_gametype { |
|
|
|
|
b"\\gametype\\a,b,c,d" => { |
|
|
|
|
gametype: Some("a,b,c,d"), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_gamedata { |
|
|
|
|
b"\\gamedata\\a,b,c,d" => { |
|
|
|
|
gamedata: Some("a,b,c,d"), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_gamedataor { |
|
|
|
|
b"\\gamedataor\\a,b,c,d" => { |
|
|
|
|
gamedataor: Some("a,b,c,d"), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_name_match { |
|
|
|
|
b"\\name_match\\localhost" => { |
|
|
|
|
name_match: Some("localhost"), |
|
|
|
@ -270,11 +219,6 @@ mod tests {
@@ -270,11 +219,6 @@ mod tests {
|
|
|
|
|
version_match: Some("1.2.3.4"), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_collapse_addr_hash { |
|
|
|
|
b"\\collapse_addr_hash\\1" => { |
|
|
|
|
collapse_addr_hash: true, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_gameaddr { |
|
|
|
|
b"\\gameaddr\\192.168.1.100" => { |
|
|
|
|
gameaddr: Some(SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 100), 0)), |
|
|
|
@ -300,12 +244,6 @@ mod tests {
@@ -300,12 +244,6 @@ mod tests {
|
|
|
|
|
flags: FilterFlags::SECURE, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_linux(flags_mask: FilterFlags::LINUX) { |
|
|
|
|
b"\\linux\\0" => {} |
|
|
|
|
b"\\linux\\1" => { |
|
|
|
|
flags: FilterFlags::LINUX, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_password(flags_mask: FilterFlags::PASSWORD) { |
|
|
|
|
b"\\password\\0" => {} |
|
|
|
|
b"\\password\\1" => { |
|
|
|
@ -324,12 +262,6 @@ mod tests {
@@ -324,12 +262,6 @@ mod tests {
|
|
|
|
|
flags: FilterFlags::FULL, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_proxy(flags_mask: FilterFlags::PROXY) { |
|
|
|
|
b"\\proxy\\0" => {} |
|
|
|
|
b"\\proxy\\1" => { |
|
|
|
|
flags: FilterFlags::PROXY, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
parse_noplayers(flags_mask: FilterFlags::NOPLAYERS) { |
|
|
|
|
b"\\noplayers\\0" => {} |
|
|
|
|
b"\\noplayers\\1" => { |
|
|
|
@ -390,14 +322,8 @@ mod tests {
@@ -390,14 +322,8 @@ mod tests {
|
|
|
|
|
" => { |
|
|
|
|
gamedir: Some("valve"), |
|
|
|
|
map: Some("crossfire"), |
|
|
|
|
appid: Some(70), |
|
|
|
|
napp: Some(60), |
|
|
|
|
gametype: Some("a,b,c,d"), |
|
|
|
|
gamedata: Some("a,b,c,d"), |
|
|
|
|
gamedataor: Some("a,b,c,d"), |
|
|
|
|
name_match: Some("localhost"), |
|
|
|
|
version_match: Some("1.2.3.4"), |
|
|
|
|
collapse_addr_hash: true, |
|
|
|
|
gameaddr: Some(SocketAddrV4::new(Ipv4Addr::new(192, 168, 1, 100), 0)), |
|
|
|
|
clver: Some("0.20"), |
|
|
|
|
flags: FilterFlags::all(), |
|
|
|
@ -448,32 +374,6 @@ mod tests {
@@ -448,32 +374,6 @@ mod tests {
|
|
|
|
|
matches!(s, b"\\dedicated\\1", 1); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn match_proxy() { |
|
|
|
|
let s = servers! { |
|
|
|
|
"0.0.0.0:0" => b"" |
|
|
|
|
"0.0.0.0:0" => b"\\type\\d" |
|
|
|
|
"0.0.0.0:0" => b"\\type\\p" |
|
|
|
|
"0.0.0.0:0" => b"\\type\\l" |
|
|
|
|
}; |
|
|
|
|
matches!(s, b"", 0, 1, 2, 3); |
|
|
|
|
matches!(s, b"\\proxy\\0", 0, 1, 3); |
|
|
|
|
matches!(s, b"\\proxy\\1", 2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn match_linux() { |
|
|
|
|
let s = servers! { |
|
|
|
|
"0.0.0.0:0" => b"" |
|
|
|
|
"0.0.0.0:0" => b"\\os\\w" |
|
|
|
|
"0.0.0.0:0" => b"\\os\\l" |
|
|
|
|
"0.0.0.0:0" => b"\\os\\m" |
|
|
|
|
}; |
|
|
|
|
matches!(s, b"", 0, 1, 2, 3); |
|
|
|
|
matches!(s, b"\\linux\\0", 0, 1, 3); |
|
|
|
|
matches!(s, b"\\linux\\1", 2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn match_password() { |
|
|
|
|
let s = servers! { |
|
|
|
|