event stream
This commit is contained in:
parent
9ebf7b0f0a
commit
a0ec314cac
5 changed files with 120 additions and 25 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -1085,6 +1085,7 @@ dependencies = [
|
||||||
"rocket_codegen",
|
"rocket_codegen",
|
||||||
"rocket_http",
|
"rocket_http",
|
||||||
"serde",
|
"serde",
|
||||||
|
"serde_json",
|
||||||
"state",
|
"state",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"time",
|
"time",
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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 ];
|
||||||
}
|
}
|
||||||
|
|
126
src/main.rs
126
src/main.rs
|
@ -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")))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue