nginx separate serving is not for debug
This commit is contained in:
parent
b72b8b4bd3
commit
f4bd578ad3
7 changed files with 64 additions and 92 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,6 +1,5 @@
|
||||||
.envrc
|
.envrc
|
||||||
.direnv
|
.direnv
|
||||||
/nixos.qcow2
|
|
||||||
|
|
||||||
# Added by cargo
|
# Added by cargo
|
||||||
|
|
||||||
|
|
12
Rocket.toml
Normal file
12
Rocket.toml
Normal 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],
|
||||||
|
]
|
62
nix/vm.nix
62
nix/vm.nix
|
@ -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";
|
|
||||||
}
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
}
|
}
|
||||||
|
|
26
src/main.rs
26
src/main.rs
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
20
src/track.rs
20
src/track.rs
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue