mirror of
https://github.com/YGGverse/hlstate-rs.git
synced 2026-03-31 17:15:37 +00:00
make tmp cli scrape impl
This commit is contained in:
parent
105409a76b
commit
e52ed711ba
8 changed files with 312 additions and 47 deletions
|
|
@ -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"
|
||||
|
|
@ -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
|
||||
```
|
||||
|
|
@ -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<String>,
|
||||
|
|
|
|||
|
|
@ -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<Meta>, global: &State<Global>) -> Result<Template, Status> {
|
||||
#[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::<Vec<_>>()
|
||||
.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<Server> = 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<Utc> {
|
||||
DateTime::<Utc>::from_timestamp(timestamp, 0).unwrap()
|
||||
}
|
||||
|
|
|
|||
33
crates/httpd/src/scrape.rs
Normal file
33
crates/httpd/src/scrape.rs
Normal file
|
|
@ -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<i32>,
|
||||
pub master_timeout: u32,
|
||||
pub server_timeout: u32,
|
||||
pub masters: Vec<SocketAddr>,
|
||||
pub filter: String,
|
||||
pub servers: Vec<Info>,
|
||||
}
|
||||
|
||||
#[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,
|
||||
}
|
||||
|
|
@ -2,11 +2,46 @@
|
|||
{% block content %}
|
||||
<h2>Game</h2>
|
||||
{% if servers %}
|
||||
{% for server in servers %}
|
||||
<div>
|
||||
<h2><a href="{{ server.host }}">{{ server.name }}</a></h2>
|
||||
</div>
|
||||
{% endfor %}
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Address</th>
|
||||
<th>Host</th>
|
||||
<th>Ping</th>
|
||||
<th>Protocol</th>
|
||||
<th>Gamedir</th>
|
||||
<th>Map</th>
|
||||
<th>Team</th>
|
||||
<th>Coop</th>
|
||||
<th>Password</th>
|
||||
<th>Dedicated</th>
|
||||
<th>DM</th>
|
||||
<th>Max</th>
|
||||
<th>Online</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
<thead>
|
||||
</tbody>
|
||||
{% for server in servers %}
|
||||
<tr>
|
||||
<td>{{ server.address }}</td>
|
||||
<td>{{ server.host }}</td>
|
||||
<td>{{ server.ping }}</td>
|
||||
<td>{{ server.protocol }}</td>
|
||||
<td>{{ server.gamedir }}</td>
|
||||
<td>{{ server.map }}</td>
|
||||
<td>{{ server.team }}</td>
|
||||
<td>{{ server.coop }}</td>
|
||||
<td>{{ server.password }}</td>
|
||||
<td>{{ server.dedicated }}</td>
|
||||
<td>{{ server.dm }}</td>
|
||||
<td>{{ server.maxcl }}</td>
|
||||
<td>{{ server.numcl }}</td>
|
||||
<td>{{ server.status }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<div>
|
||||
<p>Nobody.</p>
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue