From e52ed711ba2cb3100aac3e10c9d4b941dcedff4e Mon Sep 17 00:00:00 2001 From: yggverse Date: Thu, 5 Mar 2026 22:05:56 +0200 Subject: [PATCH] make tmp cli scrape impl --- Cargo.lock | 193 ++++++++++++++++++++++-- crates/httpd/Cargo.toml | 8 +- crates/httpd/README.md | 6 +- crates/httpd/src/config.rs | 3 +- crates/httpd/src/main.rs | 66 +++++--- crates/httpd/src/scrape.rs | 33 ++++ crates/httpd/templates/index.html.tera | 45 +++++- crates/httpd/templates/layout.html.tera | 5 +- 8 files changed, 312 insertions(+), 47 deletions(-) create mode 100644 crates/httpd/src/scrape.rs diff --git a/Cargo.lock b/Cargo.lock index cfc3695..db3b51c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,12 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + [[package]] name = "async-stream" version = "0.3.6" @@ -202,10 +208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", - "js-sys", "num-traits", - "serde", - "wasm-bindgen", "windows-link", ] @@ -479,6 +482,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -588,14 +597,15 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.4" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", "r-efi", "wasip2", + "wasip3", ] [[package]] @@ -647,6 +657,15 @@ dependencies = [ "tracing", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + [[package]] name = "hashbrown" version = "0.16.1" @@ -669,11 +688,9 @@ checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" name = "hlstate-httpd" version = "0.1.0" dependencies = [ - "chrono", "clap", "rocket", "rocket_dyn_templates", - "serde", "toml 0.9.12+spec-1.1.0", ] @@ -778,6 +795,12 @@ dependencies = [ "cc", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ignore" version = "0.4.25" @@ -801,7 +824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown", + "hashbrown 0.16.1", "serde", "serde_core", ] @@ -891,6 +914,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" version = "0.2.182" @@ -1257,6 +1286,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + [[package]] name = "proc-macro2" version = "1.0.106" @@ -1290,9 +1329,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "5.3.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" @@ -1417,6 +1456,7 @@ dependencies = [ "rocket_codegen", "rocket_http", "serde", + "serde_json", "state", "tempfile", "time", @@ -1525,6 +1565,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + [[package]] name = "serde" version = "1.0.228" @@ -1718,7 +1764,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -2091,6 +2137,15 @@ dependencies = [ "wit-bindgen", ] +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + [[package]] name = "wasm-bindgen" version = "0.2.114" @@ -2136,6 +2191,40 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + [[package]] name = "winapi-util" version = "0.1.11" @@ -2449,6 +2538,88 @@ name = "wit-bindgen" version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "yansi" diff --git a/crates/httpd/Cargo.toml b/crates/httpd/Cargo.toml index 921f5ec..c67a3ec 100644 --- a/crates/httpd/Cargo.toml +++ b/crates/httpd/Cargo.toml @@ -10,10 +10,12 @@ categories = ["parsing", "text-processing", "value-formatting"] repository = "https://github.com/YGGverse/hlstate-rs" [dependencies] -chrono = { version = "0.4.41", features = ["serde"] } +#observer = { git = "https://github.com/YGGverse/xash3d-master.git", package = "xash3d-observer", branch = "ip6-only" } +#protocol = { git = "https://github.com/YGGverse/xash3d-master.git", package = "xash3d-protocol", branch = "ip6-only" } +#observer = { path = "../../../xash3d-master/observer", package = "xash3d-observer" } +#protocol = { path = "../../../xash3d-master/protocol", package = "xash3d-protocol" } clap = { version = "4.5.54", features = ["derive"] } #mysql = { package = "hlstate-mysql", version = "0.1.0", path = "../mysql" } -rocket = "0.5.1" +rocket = { version = "0.5.1", features = ["json"] } rocket_dyn_templates = { version = "0.2.0", features = ["tera"] } -serde = { version = "1.0.228", features = ["derive"] } toml = "0.9.10" \ No newline at end of file diff --git a/crates/httpd/README.md b/crates/httpd/README.md index 4832354..259eac2 100644 --- a/crates/httpd/README.md +++ b/crates/httpd/README.md @@ -2,10 +2,10 @@ Web server implementation based on the Rocket engine -> [!NOTE] -> In development! +> [!IMPORTANT] +> * IPv6-only servers implementation, make sure `xash3d-query` ([IPv6](https://github.com/YGGverse/xash3d-master/tree/ip6-only/query)) is installed! -``` +``` bash cd crates/httpd cargo run -- -c config.toml ``` \ No newline at end of file diff --git a/crates/httpd/src/config.rs b/crates/httpd/src/config.rs index 99277b6..57c4471 100644 --- a/crates/httpd/src/config.rs +++ b/crates/httpd/src/config.rs @@ -1,10 +1,11 @@ -use serde::Deserialize; +use rocket::serde::Deserialize; use std::{ collections::HashSet, net::{IpAddr, SocketAddr}, }; #[derive(Debug, Deserialize)] +#[serde(crate = "rocket::serde")] pub struct Config { pub debug: bool, pub description: Option, diff --git a/crates/httpd/src/main.rs b/crates/httpd/src/main.rs index e05a8c6..db31415 100644 --- a/crates/httpd/src/main.rs +++ b/crates/httpd/src/main.rs @@ -5,30 +5,58 @@ mod argument; mod config; mod global; mod meta; +mod scrape; -use chrono::{DateTime, Utc}; use global::Global; use meta::Meta; -use rocket::{State, http::Status, serde::Serialize}; +use rocket::{State, http::Status}; use rocket_dyn_templates::{Template, context}; #[get("/")] fn index(meta: &State, global: &State) -> Result { - #[derive(Serialize)] - #[serde(crate = "rocket::serde")] - struct Server { - name: String, + // @TODO: requires library impl + // https://github.com/FWGS/xash3d-master/issues/4 + let scrape = std::process::Command::new("xash3d-query") + .arg("all") + .arg("-M") + .arg( + global + .masters + .iter() + .map(|a| a.to_string()) + .collect::>() + .join(","), + ) + .arg("-j") + .output() + .map_err(|e| { + error!("Make sure `xash3d-query` is installed: {e}"); + Status::InternalServerError + })?; + if scrape.status.success() { + let result: scrape::Result = rocket::serde::json::serde_json::from_str( + str::from_utf8(&scrape.stdout).map_err(|e| { + error!("stdout parse error: {e}"); + Status::InternalServerError + })?, + ) + .map_err(|e| { + error!("JSON parse error: {e}"); + Status::InternalServerError + })?; + Ok(Template::render( + "index", + context! { + masters: &global.masters, + title: &meta.title, + version: &meta.version, + servers: result.servers, + }, + )) + } else { + error!("Make sure `xash3d-query` is installed!"); + Err(Status::InternalServerError) } - let servers: Vec = Vec::new(); - Ok(Template::render( - "index", - context! { - masters: &global.masters, - servers: servers, - title: &meta.title, - version: &meta.version, - }, - )) } #[launch] @@ -59,9 +87,3 @@ fn rocket() -> _ { }) .mount("/", routes![index]) } - -const S: &str = " • "; - -fn time(timestamp: i64) -> DateTime { - DateTime::::from_timestamp(timestamp, 0).unwrap() -} diff --git a/crates/httpd/src/scrape.rs b/crates/httpd/src/scrape.rs new file mode 100644 index 0000000..8fd0624 --- /dev/null +++ b/crates/httpd/src/scrape.rs @@ -0,0 +1,33 @@ +use rocket::serde::{Deserialize, Serialize}; +use std::net::SocketAddr; + +#[derive(Debug, Deserialize, Serialize)] +#[serde(crate = "rocket::serde")] +pub struct Result { + pub protocol: Vec, + pub master_timeout: u32, + pub server_timeout: u32, + pub masters: Vec, + pub filter: String, + pub servers: Vec, +} + +#[derive(Debug, Deserialize, Serialize)] +#[serde(crate = "rocket::serde")] +pub struct Info { + pub time: i64, + pub address: SocketAddr, + pub ping: f64, + pub status: String, + pub gamedir: String, + pub map: String, + pub host: String, + pub protocol: i32, + pub numcl: u32, + pub maxcl: u32, + pub dm: bool, + pub team: bool, + pub coop: bool, + pub password: bool, + pub dedicated: bool, +} diff --git a/crates/httpd/templates/index.html.tera b/crates/httpd/templates/index.html.tera index 7f5d091..4a9984d 100644 --- a/crates/httpd/templates/index.html.tera +++ b/crates/httpd/templates/index.html.tera @@ -2,11 +2,46 @@ {% block content %}

Game

{% if servers %} - {% for server in servers %} - - {% endfor %} + + + + + + + + + + + + + + + + + + + + + {% for server in servers %} + + + + + + + + + + + + + + + + + {% endfor %} + +
AddressHostPingProtocolGamedirMapTeamCoopPasswordDedicatedDMMaxOnlineStatus
{{ server.address }}{{ server.host }}{{ server.ping }}{{ server.protocol }}{{ server.gamedir }}{{ server.map }}{{ server.team }}{{ server.coop }}{{ server.password }}{{ server.dedicated }}{{ server.dm }}{{ server.maxcl }}{{ server.numcl }}{{ server.status }}
{% else %}

Nobody.

diff --git a/crates/httpd/templates/layout.html.tera b/crates/httpd/templates/layout.html.tera index eddbb9c..a13e1b4 100644 --- a/crates/httpd/templates/layout.html.tera +++ b/crates/httpd/templates/layout.html.tera @@ -9,7 +9,7 @@ padding: 0; font-family: monospace; color-scheme: light dark; - --container-max-width: 768px; + --container-max-width: 1024px; --color-success: #4bc432; --color-warning: #f37b21; --color-error: #ff6363; @@ -47,15 +47,16 @@ } table { - width: 100%; border-collapse: collapse; border: 1px solid var(--color-default); + width: 100%; } table th, table td { border: 1px solid var(--color-default); padding: 4px; + text-align: center; } table tr:hover td {