event stream

This commit is contained in:
catvayor 2024-05-16 22:24:47 +02:00
parent 9ebf7b0f0a
commit a0ec314cac
5 changed files with 120 additions and 25 deletions

1
Cargo.lock generated
View file

@ -1085,6 +1085,7 @@ dependencies = [
"rocket_codegen", "rocket_codegen",
"rocket_http", "rocket_http",
"serde", "serde",
"serde_json",
"state", "state",
"tempfile", "tempfile",
"time", "time",

View file

@ -5,8 +5,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies.rocket]
rocket = "0.5.0" version = "0.5.0"
features = ["json"]
[dependencies.rocket_dyn_templates] [dependencies.rocket_dyn_templates]
version = "0.1.0" version = "0.1.0"

View file

@ -3,5 +3,5 @@ let
fenix = import (fetchTarball "https://github.com/nix-community/fenix/archive/main.tar.gz") { }; fenix = import (fetchTarball "https://github.com/nix-community/fenix/archive/main.tar.gz") { };
in in
pkgs.mkShell { pkgs.mkShell {
buildInputs = with fenix.latest; [ cargo rustc ]; buildInputs = with fenix.latest; [ cargo rustc rustfmt ];
} }

View file

@ -1,11 +1,17 @@
#[macro_use] extern crate rocket; #[macro_use]
use rocket::fs::{FileServer, relative}; extern crate rocket;
use rocket::State; use rocket::{
use std::{ fs::{relative, FileServer},
collections::HashMap, response::stream::{Event, EventStream},
sync::RwLock, serde::Serialize,
tokio::{
select,
time::{self, Duration},
},
Shutdown, State,
}; };
use rocket_dyn_templates::{Template, context}; use rocket_dyn_templates::{context, Template};
use std::{collections::HashMap, sync::RwLock};
enum TrackedState { enum TrackedState {
Conscrit { Conscrit {
@ -19,7 +25,7 @@ enum TrackedState {
Vieux { Vieux {
color: u8, color: u8,
invisible: bool, invisible: bool,
} },
} }
struct Tracked { struct Tracked {
@ -28,20 +34,90 @@ struct Tracked {
state: TrackedState, state: TrackedState,
} }
fn build_conscrit(name: String) -> Tracked {
Tracked {
name: name,
pos: (0.0, 0.0),
state: TrackedState::Conscrit {
invisible: false,
blurred: false,
captured: false,
malette: false,
invisibility_codes: 0,
blur_codes: 0,
},
}
}
fn build_vieux(name: String) -> Tracked {
Tracked {
name: name,
pos: (0.0, 0.0),
state: TrackedState::Vieux {
invisible: true,
color: 1,
},
}
}
type Tracking = RwLock<HashMap<String, RwLock<Tracked>>>; type Tracking = RwLock<HashMap<String, RwLock<Tracked>>>;
#[get("/track/conscrit")] #[derive(Serialize)]
fn conscrit() -> Template{ #[serde(crate = "rocket::serde")]
Template::render("conscrit", context!{ struct TrackedInfo {
name: "un nom", name: String,
id: "ID", pos: (f32, f32),
gpslog: "no" }
#[get("/track/<id>?<gpslog>")]
fn tracked_view(id: &str, gpslog: Option<bool>, tracking: &State<Tracking>) -> Option<Template> {
if let Some(tracked) = tracking.read().unwrap().get(&id.to_string()) {
Some(Template::render(
match tracked.read().unwrap().state {
TrackedState::Vieux { .. } => "vieux",
TrackedState::Conscrit { .. } => "conscrit",
},
context! {
name: &tracked.read().unwrap().name,
id: &id,
gpslog: gpslog.unwrap_or(true)
},
))
} else {
None
}
}
#[get("/track/<id>/events")]
fn tracked_events<'a>(
id: &'a str,
tracking: &'a State<Tracking>,
mut shutdown: Shutdown,
) -> Option<EventStream![Event + 'a]> {
if tracking.read().unwrap().contains_key(&id.to_string()) {
Some(EventStream! {
let mut interval = time::interval(Duration::from_secs(5));
loop {
select!{
_ = interval.tick() => {
let info = TrackedInfo {
name: id.to_string(),
pos: tracking.read().unwrap().get(&id.to_string()).unwrap().read().unwrap().pos
};
yield Event::json(&info).event("coords")
},
_ = &mut shutdown => break
}
}
}) })
} else {
None
}
} }
#[put("/track/<id>?<lat>&<long>")] #[put("/track/<id>?<lat>&<long>")]
fn store_pos(id: String, lat: f32, long: f32, tracking: &State<Tracking>){ fn store_pos(id: &str, lat: f32, long: f32, tracking: &State<Tracking>) {
if let Some(tracked) = tracking.read().unwrap().get(&id) { if let Some(tracked) = tracking.read().unwrap().get(&id.to_string()) {
tracked.write().unwrap().pos = (lat, long); tracked.write().unwrap().pos = (lat, long);
} }
} }
@ -54,10 +130,26 @@ fn index() -> &'static str {
#[launch] #[launch]
fn rocket() -> _ { fn rocket() -> _ {
let tracking = HashMap::<String, RwLock<Tracked>>::from([ let tracking = HashMap::<String, RwLock<Tracked>>::from([
(
"team00".to_string(),
RwLock::new(build_conscrit("Équipe 0".to_string())),
),
(
"team01".to_string(),
RwLock::new(build_conscrit("Équipe 1".to_string())),
),
(
"npc0".to_string(),
RwLock::new(build_vieux("PNJ 0".to_string())),
),
(
"npc1".to_string(),
RwLock::new(build_vieux("PNJ 1".to_string())),
),
]); ]);
rocket::build() rocket::build()
.attach(Template::fairing()) .attach(Template::fairing())
.manage(RwLock::new(tracking)) .manage(RwLock::new(tracking))
.mount("/", routes![index, store_pos, conscrit]) .mount("/", routes![index, store_pos, tracked_view, tracked_events])
.mount("/", FileServer::from(relative!("static"))) .mount("/", FileServer::from(relative!("static")))
} }

View file

@ -13,9 +13,6 @@
integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ==" integrity="sha512-BB3hKbKWOc9Ez/TAwyWxNXeoV9c1v6FIeYiBieIWkpLjauysF18NzgR1MBNBXf8/KABdlkX68nAhlwcDFLGPCQ=="
crossorigin=""></script> crossorigin=""></script>
<!-- SOCKET.IO INCLUDE -->
<script src="/socket.io/socket.io.js"></script>
<style type="text/css"> <style type="text/css">
#map { height: 600px; } #map { height: 600px; }
#codes { #codes {
@ -27,7 +24,7 @@
} }
</style> </style>
<script type="text/javascript" src="/utils.js"></script> <!-- <script type="text/javascript" src="/utils.js"></script> -->
</head> </head>
<body> <body>
<div id="map"></div><br/> <div id="map"></div><br/>
@ -39,6 +36,10 @@
</div> </div>
<script type="text/javascript"> <script type="text/javascript">
const evtSource = new EventSource("/track/{{id}}/events");
evtSource.addEventListener("coords", (event) => {
console.log(event);
});
// ////////////////////////////////////////////////////////////////////////////// // //////////////////////////////////////////////////////////////////////////////
// // SETUP MAP // // SETUP MAP