nginx separate serving is not for debug

This commit is contained in:
catvayor 2024-06-14 00:01:57 +02:00
parent b72b8b4bd3
commit f4bd578ad3
7 changed files with 64 additions and 92 deletions

1
.gitignore vendored
View file

@ -1,6 +1,5 @@
.envrc .envrc
.direnv .direnv
/nixos.qcow2
# Added by cargo # Added by cargo

12
Rocket.toml Normal file
View file

@ -0,0 +1,12 @@
[debug]
blurred_move = [0.0005, 0.0005]
bonus_timeout = 5000
event_timeout = 100
admin_token = "root"
serve_static = true
base_teams = [
["team00", "Équipe 00", false],
["team01", "Équipe 01", false],
["npc0", "PNJ 0", true],
["npc1", "PNJ 1", true],
]

View file

@ -1,62 +0,0 @@
{ pkgs, lib, ... }:
{
nix = {
nixPath = [
"nixpkgs=${builtins.storePath pkgs.path}"
"nixos=${builtins.storePath pkgs.path}"
];
package = pkgs.lix;
};
environment.systemPackages = with pkgs; [ wget tmux ];
services.nginx = {
enable = true;
virtualHosts."localhost" = {
default = true;
locations = {
"/" = {
root = "/traque/static";
tryFiles = "$uri @backend";
};
"@backend" = {
recommendedProxySettings = true;
proxyPass = "http://localhost:8000";
extraConfig = ''
proxy_set_header Connection ''';
proxy_http_version 1.1;
chunked_transfer_encoding off;
proxy_buffering off;
proxy_cache off;
'';
};
};
#extraConfig = ''
# error_page 502 =503;
#'';
};
};
services.getty = {
autologinUser = "root";
helpLine = lib.mkForce ''
On serial console: type Ctrl-a c to switch to the qemu console and `quit` to stop the VM.
traque source is on /traque (rw), `cd /traque && ./target/debug/traque` to run the test.
Compile from the host for performance (the VM is highly limited).'';
};
nixos-shell.mounts = {
mountHome = false;
mountNixProfile = false;
cache = "none";
extraMounts = {
"/traque" = {
target = toString ../.;
cache = "none";
};
};
};
virtualisation = {
forwardPorts = [
{ from = "host"; host.port = 8000; guest.port = 80; }
];
};
system.stateVersion = "24.11";
}

View file

@ -3,7 +3,7 @@ use rocket::{
serde::json::Json, serde::json::Json,
tokio::{ tokio::{
select, select,
time::{self}, time::{self, Duration},
}, },
Route, Shutdown, State, Route, Shutdown, State,
}; };
@ -54,6 +54,7 @@ fn admin_events<'a>(
admin_key: &State<AdminKey>, admin_key: &State<AdminKey>,
admin_queue: &'a State<AdminEventQueue>, admin_queue: &'a State<AdminEventQueue>,
tracking: &State<Tracking>, tracking: &State<Tracking>,
config: &State<Config>,
mut shutdown: Shutdown, mut shutdown: Shutdown,
) -> Option<EventStream![Event + 'a]> { ) -> Option<EventStream![Event + 'a]> {
if tok == Some(admin_key.to_string()) { if tok == Some(admin_key.to_string()) {
@ -63,13 +64,14 @@ fn admin_events<'a>(
.iter() .iter()
.map(|(_, tracked)| admin_view(&tracked.read().unwrap())) .map(|(_, tracked)| admin_view(&tracked.read().unwrap()))
.collect(); .collect();
let timeout = Duration::from_millis(config.event_timeout);
Some(EventStream! { Some(EventStream! {
yield Event::json(&full_info).event("full_update"); yield Event::json(&full_info).event("full_update");
let mut interval = time::interval(EVENT_TIMEOUT); let mut interval = time::interval(timeout);
loop { loop {
select!{ select!{
_ = interval.tick() =>{ _ = interval.tick() =>{
for evt in evts_to_send(admin_queue){ for evt in evts_to_send(admin_queue, timeout){
//println!("{:?}", evt); //println!("{:?}", evt);
yield evt; yield evt;
} }

View file

@ -9,9 +9,16 @@ use std::{
sync::{Arc, RwLock}, sync::{Arc, RwLock},
}; };
pub const BLURRED_MOVE: (f32, f32) = (0.0005, 0.0005); #[derive(Deserialize)]
pub const BONUS_TIMEOUT: Duration = Duration::from_millis(5000); #[serde(crate = "rocket::serde")]
pub const EVENT_TIMEOUT: Duration = Duration::from_millis(100); pub struct Config {
pub blurred_move : (f32, f32),
pub bonus_timeout : u64,
pub event_timeout : u64,
pub admin_token : String,
pub base_teams : Vec<(String, String, bool)>,
pub serve_static : bool,
}
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
#[serde(crate = "rocket::serde")] #[serde(crate = "rocket::serde")]
@ -135,8 +142,8 @@ pub struct QueuedEvent {
} }
impl QueuedEvent { impl QueuedEvent {
pub fn expired(&self) -> bool { pub fn expired(&self, timeout: Duration) -> bool {
self.date.elapsed() >= EVENT_TIMEOUT self.date.elapsed() >= timeout
} }
} }
impl From<Event> for QueuedEvent { impl From<Event> for QueuedEvent {
@ -204,7 +211,7 @@ pub fn admin_view(team: &Tracked) -> AdminTrackedInfo {
} }
} }
pub fn apparent_info(watcher: &Tracked, team: &Tracked) -> Option<TrackedInfo> { pub fn apparent_info(watcher: &Tracked, team: &Tracked, blurred_move : (f32, f32)) -> Option<TrackedInfo> {
if watcher.id == team.id { if watcher.id == team.id {
None None
} else if let Conscrit { } else if let Conscrit {
@ -219,8 +226,8 @@ pub fn apparent_info(watcher: &Tracked, team: &Tracked) -> Option<TrackedInfo> {
let (lat, lon) = team.pos; let (lat, lon) = team.pos;
Some(TrackedInfo { Some(TrackedInfo {
pos: ( pos: (
lat + BLURRED_MOVE.0 * (rng.gen::<f32>() * 2.0 - 1.0), lat + blurred_move.0 * (rng.gen::<f32>() * 2.0 - 1.0),
lon + BLURRED_MOVE.1 * (rng.gen::<f32>() * 2.0 - 1.0), lon + blurred_move.1 * (rng.gen::<f32>() * 2.0 - 1.0),
), ),
..base_view(team) ..base_view(team)
}) })
@ -239,12 +246,12 @@ pub fn apparent_info(watcher: &Tracked, team: &Tracked) -> Option<TrackedInfo> {
} }
} }
pub fn evts_to_send(evt_queue: &RwLock<VecDeque<QueuedEvent>>) -> Vec<Event> { pub fn evts_to_send(evt_queue: &RwLock<VecDeque<QueuedEvent>>, timeout: Duration) -> Vec<Event> {
evt_queue evt_queue
.read() .read()
.unwrap() .unwrap()
.iter() .iter()
.filter(|qevt| !qevt.expired()) .filter(|qevt| !qevt.expired(timeout))
.map(|qevt| qevt.evt.clone()) .map(|qevt| qevt.evt.clone())
.collect() .collect()
} }

View file

@ -1,6 +1,8 @@
#[macro_use] #[macro_use]
extern crate rocket; extern crate rocket;
use rocket::{ use rocket::{
fs::{relative, FileServer},
fairing::AdHoc,
response::stream::Event, response::stream::Event,
tokio::{ tokio::{
self, select, self, select,
@ -23,13 +25,13 @@ fn index() -> &'static str {
"Hello, world!" "Hello, world!"
} }
fn send_coords(tracking: &Tracking, evt_queue: &TrackingEventQueue) { fn send_coords(tracking: &Tracking, evt_queue: &TrackingEventQueue, config: &Config) {
let tracking_lock = tracking.read().unwrap(); let tracking_lock = tracking.read().unwrap();
for (id, queue) in evt_queue.read().unwrap().iter() { for (id, queue) in evt_queue.read().unwrap().iter() {
let watcher = tracking_lock.get(id).unwrap().read().unwrap(); let watcher = tracking_lock.get(id).unwrap().read().unwrap();
let mut infos: Vec<TrackedInfo> = Vec::new(); let mut infos: Vec<TrackedInfo> = Vec::new();
for (_, tracked) in tracking_lock.iter() { for (_, tracked) in tracking_lock.iter() {
if let Some(info) = apparent_info(&watcher, &tracked.read().unwrap()) { if let Some(info) = apparent_info(&watcher, &tracked.read().unwrap(), config.blurred_move) {
infos.push(info); infos.push(info);
} }
} }
@ -40,11 +42,11 @@ fn send_coords(tracking: &Tracking, evt_queue: &TrackingEventQueue) {
} }
} }
fn clean_expired_evt(evt_queues: &TrackingEventQueue, admin_queue: &AdminEventQueue) { fn clean_expired_evt(evt_queues: &TrackingEventQueue, admin_queue: &AdminEventQueue, config: &Config) {
for (_, queue) in evt_queues.read().unwrap().iter() { for (_, queue) in evt_queues.read().unwrap().iter() {
let queue = &mut queue.write().unwrap(); let queue = &mut queue.write().unwrap();
while let Some(queued_evt) = queue.front() { while let Some(queued_evt) = queue.front() {
if queued_evt.expired() { if queued_evt.expired(Duration::from_millis(config.event_timeout)) {
queue.pop_front(); queue.pop_front();
} else { } else {
break; break;
@ -53,7 +55,7 @@ fn clean_expired_evt(evt_queues: &TrackingEventQueue, admin_queue: &AdminEventQu
} }
let queue = &mut admin_queue.write().unwrap(); let queue = &mut admin_queue.write().unwrap();
while let Some(queued_evt) = queue.front() { while let Some(queued_evt) = queue.front() {
if queued_evt.expired() { if queued_evt.expired(Duration::from_millis(config.event_timeout)) {
queue.pop_front(); queue.pop_front();
} else { } else {
break; break;
@ -63,6 +65,8 @@ fn clean_expired_evt(evt_queues: &TrackingEventQueue, admin_queue: &AdminEventQu
#[launch] #[launch]
async fn rocket() -> _ { async fn rocket() -> _ {
let rocket = rocket::build();
let config : Config = rocket.figment().extract().unwrap();
//TODO: read a config file on release //TODO: read a config file on release
let tracking: Tracking = Arc::new(RwLock::new(HashMap::from([ let tracking: Tracking = Arc::new(RwLock::new(HashMap::from([
( (
@ -93,8 +97,9 @@ async fn rocket() -> _ {
let admin_evt_queue: AdminEventQueue = Arc::new(RwLock::new(VecDeque::new())); let admin_evt_queue: AdminEventQueue = Arc::new(RwLock::new(VecDeque::new()));
let key: AdminKey = "root".to_string(); //TODO : random on release let key: AdminKey = "root".to_string(); //TODO : random on release
println!("Admin token: {}", key); println!("Admin token: {}", key);
let rocket = rocket::build() let mut rocket = rocket
.attach(Template::fairing()) .attach(Template::fairing())
.attach(AdHoc::config::<Config>())
.manage(tracking.clone()) .manage(tracking.clone())
.manage(evt_queue.clone()) .manage(evt_queue.clone())
.manage(admin_evt_queue.clone()) .manage(admin_evt_queue.clone())
@ -102,13 +107,16 @@ async fn rocket() -> _ {
.mount("/", routes![index]) .mount("/", routes![index])
.mount("/track", track::routes()) .mount("/track", track::routes())
.mount("/admin", admin::routes()); .mount("/admin", admin::routes());
if config.serve_static {
rocket = rocket.mount("/", FileServer::from(relative!("static")));
}
tokio::spawn(async move { tokio::spawn(async move {
let mut clean_interval = time::interval(5 * EVENT_TIMEOUT); let mut clean_interval = time::interval(5 * Duration::from_millis(config.event_timeout));
let mut coord_interval = time::interval(Duration::from_millis(3000)); let mut coord_interval = time::interval(Duration::from_millis(3000));
loop { loop {
select! { select! {
_ = coord_interval.tick() => send_coords(&tracking, &evt_queue), _ = coord_interval.tick() => send_coords(&tracking, &evt_queue, &config),
_ = clean_interval.tick() => clean_expired_evt(&evt_queue, &admin_evt_queue), _ = clean_interval.tick() => clean_expired_evt(&evt_queue, &admin_evt_queue, &config),
} }
} }
}); });

View file

@ -2,7 +2,7 @@ use rocket::{
response::stream::{Event, EventStream}, response::stream::{Event, EventStream},
tokio::{ tokio::{
self, select, self, select,
time::{self, sleep}, time::{self, sleep, Duration},
}, },
Route, Shutdown, State, Route, Shutdown, State,
}; };
@ -35,23 +35,25 @@ fn tracked_view(
} }
} }
fn evts_for(id: &str, evt_queues: &TrackingEventQueue) -> Vec<Event> { fn evts_for(id: &str, evt_queues: &TrackingEventQueue, timeout: Duration) -> Vec<Event> {
evts_to_send(evt_queues.read().unwrap().get(&id.to_string()).unwrap()) evts_to_send(evt_queues.read().unwrap().get(&id.to_string()).unwrap(), timeout)
} }
#[get("/<id>/events")] #[get("/<id>/events")]
fn tracked_events<'a>( fn tracked_events<'a>(
id: &'a str, id: &'a str,
evt_queue: &'a State<TrackingEventQueue>, evt_queue: &'a State<TrackingEventQueue>,
config: &State<Config>,
mut shutdown: Shutdown, mut shutdown: Shutdown,
) -> Option<EventStream![Event + 'a]> { ) -> Option<EventStream![Event + 'a]> {
if evt_queue.read().unwrap().contains_key(&id.to_string()) { if evt_queue.read().unwrap().contains_key(&id.to_string()) {
let timeout = Duration::from_millis(config.event_timeout);
Some(EventStream! { Some(EventStream! {
let mut interval = time::interval(EVENT_TIMEOUT); let mut interval = time::interval(timeout);
loop { loop {
select!{ select!{
_ = interval.tick() =>{ _ = interval.tick() =>{
for evt in evts_for(id, evt_queue){ for evt in evts_for(id, evt_queue, timeout){
//println!("{:?}", evt); //println!("{:?}", evt);
yield evt; yield evt;
} }
@ -111,6 +113,7 @@ pub async fn activate_invisibility(
tracking: &State<Tracking>, tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>, evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>, admin_queue: &State<AdminEventQueue>,
config: &State<Config>,
) -> Option<()> { ) -> Option<()> {
let tracking_lock = tracking.read().unwrap(); let tracking_lock = tracking.read().unwrap();
let tracked = &mut tracking_lock.get(&id.to_string()).unwrap().write().unwrap(); let tracked = &mut tracking_lock.get(&id.to_string()).unwrap().write().unwrap();
@ -128,8 +131,9 @@ pub async fn activate_invisibility(
let queue_clone = (*evt_queues).clone(); let queue_clone = (*evt_queues).clone();
let admin_clone = (*admin_queue).clone(); let admin_clone = (*admin_queue).clone();
let id_str = id.to_string(); let id_str = id.to_string();
let timeout = Duration::from_millis(config.bonus_timeout);
tokio::spawn(async move { tokio::spawn(async move {
sleep(BONUS_TIMEOUT).await; sleep(timeout).await;
if let Conscrit { if let Conscrit {
ref mut invisible, .. ref mut invisible, ..
} = track_clone } = track_clone
@ -170,6 +174,7 @@ pub async fn activate_blur(
tracking: &State<Tracking>, tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>, evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>, admin_queue: &State<AdminEventQueue>,
config: &State<Config>,
) -> Option<()> { ) -> Option<()> {
let tracking_lock = tracking.read().unwrap(); let tracking_lock = tracking.read().unwrap();
let tracked = &mut tracking_lock.get(&id.to_string()).unwrap().write().unwrap(); let tracked = &mut tracking_lock.get(&id.to_string()).unwrap().write().unwrap();
@ -187,8 +192,9 @@ pub async fn activate_blur(
let queue_clone = (*evt_queues).clone(); let queue_clone = (*evt_queues).clone();
let admin_clone = (*admin_queue).clone(); let admin_clone = (*admin_queue).clone();
let id_str = id.to_string(); let id_str = id.to_string();
let timeout = Duration::from_millis(config.bonus_timeout);
tokio::spawn(async move { tokio::spawn(async move {
sleep(BONUS_TIMEOUT).await; sleep(timeout).await;
if let Conscrit { if let Conscrit {
ref mut blurred, .. ref mut blurred, ..
} = track_clone } = track_clone