mirror of
https://github.com/YGGverse/hlstate-rs.git
synced 2026-04-01 01:25:38 +00:00
implement state update on background (basics for subscription feature)
This commit is contained in:
parent
e77d101b70
commit
8daa729bf9
8 changed files with 167 additions and 96 deletions
|
|
@ -14,4 +14,5 @@ pub struct Config {
|
|||
pub port: u16,
|
||||
pub query: PathBuf,
|
||||
pub title: String,
|
||||
pub refresh: u64,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,64 +7,82 @@ mod global;
|
|||
mod meta;
|
||||
mod scrape;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use global::Global;
|
||||
use meta::Meta;
|
||||
use rocket::{State, http::Status};
|
||||
use rocket::{
|
||||
State,
|
||||
http::Status,
|
||||
tokio::{spawn, sync::RwLock, time::sleep},
|
||||
};
|
||||
use rocket_dyn_templates::{Template, context};
|
||||
use std::{collections::HashSet, net::SocketAddr, path::PathBuf, sync::Arc, time::Duration};
|
||||
|
||||
struct Online {
|
||||
scrape: scrape::Result,
|
||||
update: DateTime<Utc>,
|
||||
}
|
||||
type Snap = Arc<RwLock<Option<Online>>>;
|
||||
|
||||
#[get("/")]
|
||||
fn index(meta: &State<Meta>, global: &State<Global>) -> Result<Template, Status> {
|
||||
// @TODO: requires library impl
|
||||
// https://github.com/FWGS/xash3d-master/issues/4
|
||||
let scrape = std::process::Command::new(&global.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)
|
||||
}
|
||||
async fn index(
|
||||
meta: &State<Meta>,
|
||||
global: &State<Global>,
|
||||
online: &State<Snap>,
|
||||
) -> Result<Template, Status> {
|
||||
let snap = online.read().await;
|
||||
Ok(Template::render(
|
||||
"index",
|
||||
context! {
|
||||
masters: &global.masters,
|
||||
title: &meta.title,
|
||||
version: &meta.version,
|
||||
servers: snap.as_ref().map(|s|s.scrape.servers.clone()),
|
||||
updated: snap.as_ref().map(|s|s.update.to_rfc2822())
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
#[launch]
|
||||
fn rocket() -> _ {
|
||||
async fn rocket() -> _ {
|
||||
use clap::Parser;
|
||||
let argument = argument::Argument::parse();
|
||||
let config: config::Config =
|
||||
toml::from_str(&std::fs::read_to_string(argument.config).unwrap()).unwrap();
|
||||
let online: Snap = Arc::new(RwLock::new(None));
|
||||
spawn({
|
||||
let online = online.clone();
|
||||
let query = config.query.clone();
|
||||
let masters = config.masters.clone();
|
||||
async move {
|
||||
loop {
|
||||
match scrape(&query, &masters) {
|
||||
Ok(s) => match str::from_utf8(&s.stdout) {
|
||||
Ok(r) => {
|
||||
if s.status.success() {
|
||||
*online.write().await =
|
||||
match rocket::serde::json::serde_json::from_str(r) {
|
||||
Ok(scrape) => Some(Online {
|
||||
scrape,
|
||||
update: Utc::now(),
|
||||
}),
|
||||
Err(e) => {
|
||||
error!("Could not decode scrape response: `{e}`");
|
||||
None
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!("Scrape request failed");
|
||||
}
|
||||
}
|
||||
Err(e) => error!("Could not decode UTF-8: `{e}`"),
|
||||
},
|
||||
Err(e) => error!("Scrape error: `{e}`"),
|
||||
}
|
||||
sleep(Duration::from_secs(config.refresh)).await;
|
||||
}
|
||||
}
|
||||
});
|
||||
rocket::build()
|
||||
.attach(Template::fairing())
|
||||
.configure(rocket::Config {
|
||||
|
|
@ -76,6 +94,7 @@ fn rocket() -> _ {
|
|||
rocket::Config::release_default()
|
||||
}
|
||||
})
|
||||
.manage(online)
|
||||
.manage(Global {
|
||||
masters: config.masters,
|
||||
query: config.query,
|
||||
|
|
@ -86,3 +105,24 @@ fn rocket() -> _ {
|
|||
})
|
||||
.mount("/", routes![index])
|
||||
}
|
||||
|
||||
/// Get servers online using `bin` from given `masters`
|
||||
fn scrape(
|
||||
bin: &PathBuf,
|
||||
masters: &HashSet<SocketAddr>,
|
||||
) -> Result<std::process::Output, std::io::Error> {
|
||||
// @TODO: requires library impl
|
||||
// https://github.com/FWGS/xash3d-master/issues/4
|
||||
std::process::Command::new(bin)
|
||||
.arg("all")
|
||||
.arg("-M")
|
||||
.arg(
|
||||
masters
|
||||
.iter()
|
||||
.map(|a| a.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(","),
|
||||
)
|
||||
.arg("-j")
|
||||
.output()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ pub struct Result {
|
|||
pub servers: Vec<Info>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
#[derive(Debug, Deserialize, Serialize, Clone)]
|
||||
#[serde(crate = "rocket::serde")]
|
||||
pub struct Info {
|
||||
pub time: i64,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue