traque/src/track.rs
2024-06-17 15:39:56 +02:00

230 lines
6.6 KiB
Rust

use rocket::{
http::Status,
response::stream::{Event, EventStream},
tokio::{
self, select,
time::{self, sleep, Duration},
},
Route, Shutdown, State,
};
use rocket_dyn_templates::{context, Template};
use crate::global::{TrackedState::*, *};
#[get("/")]
fn no_id() -> Status {
Status::ImATeapot
}
#[get("/<id>?<gpslog>&<dbg>")]
fn tracked_view(
id: &str,
gpslog: Option<bool>,
dbg: Option<bool>,
tracking: &State<Tracking>,
) -> Result<Template, Status> {
if let Some(tracked) = tracking.get(&id.to_string()) {
Ok(Template::render(
match tracked.read().unwrap().state {
Vieux { .. } => "vieux",
Conscrit { .. } => "conscrit",
},
context! {
name: &tracked.read().unwrap().name,
id: &id,
gpslog: gpslog.unwrap_or(true),
dbg: dbg.unwrap_or(false),
},
))
} else {
Err(Status::BadRequest)
}
}
#[get("/<id>/events")]
fn tracked_events<'a>(
id: &'a str,
evt_queue: &'a State<TrackingEventQueue>,
config: &State<Config>,
mut shutdown: Shutdown,
) -> Result<EventStream![Event + 'a], Status> {
if evt_queue.contains_key(&id.to_string()) {
let timeout = Duration::from_millis(config.event_timeout);
Ok(EventStream! {
let mut interval = time::interval(timeout);
loop {
select!{
_ = interval.tick() =>{
for evt in evts_to_send(evt_queue.get(&id.to_string()).unwrap(), timeout){
//println!("{:?}", evt);
yield evt;
}
},
_ = &mut shutdown => break
}
}
})
} else {
Err(Status::BadRequest)
}
}
#[put("/<id>/pos?<lat>&<long>")]
fn store_pos(
id: &str,
lat: f32,
long: f32,
tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
) -> Status {
if let Some(tracked) = tracking.get(&id.to_string()) {
tracked.write().unwrap().pos = (lat, long);
state_update(&tracked.read().unwrap(), &evt_queues, &admin_queue);
Status::Accepted
} else {
Status::BadRequest
}
}
#[put("/<id>/state?<inv>&<col>")]
fn set_state(
id: &str,
inv: bool,
col: u8,
tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
) -> Status {
if let Some(tracked) = tracking.get(&id.to_string()) {
let tracked = &mut tracked.write().unwrap();
if let Vieux {
ref mut invisible,
ref mut color,
} = tracked.state
{
*invisible = inv;
*color = col;
state_update(&tracked, &evt_queues, &admin_queue);
Status::Accepted
} else {
Status::MethodNotAllowed
}
} else {
Status::BadRequest
}
}
#[put("/<id>/vanish")]
pub async fn activate_invisibility(
id: &str,
tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
config: &State<Config>,
) -> Status {
if let Some(tracked) = tracking.get(&id.to_string()) {
let tracked = &mut tracked.write().unwrap();
if let Conscrit {
ref mut invisible,
ref mut invisibility_codes,
..
} = tracked.state
{
if *invisibility_codes > 0 {
*invisibility_codes -= 1;
*invisible = true;
state_update(&tracked, &evt_queues, &admin_queue);
let track_clone = (*tracking).clone();
let queue_clone = (*evt_queues).clone();
let admin_clone = (*admin_queue).clone();
let id_str = id.to_string();
let timeout = Duration::from_millis(config.bonus_timeout);
tokio::spawn(async move {
sleep(timeout).await;
if let Conscrit {
ref mut invisible, ..
} = track_clone.get(&id_str).unwrap().write().unwrap().state
{
*invisible = false;
}
state_update(
&track_clone.get(&id_str).unwrap().read().unwrap(),
&queue_clone,
&admin_clone,
);
});
Status::Accepted
} else {
Status::PaymentRequired
}
} else {
Status::MethodNotAllowed
}
} else {
Status::BadRequest
}
}
#[put("/<id>/blur")]
pub async fn activate_blur(
id: &str,
tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
config: &State<Config>,
) -> Status {
if let Some(tracked) = tracking.get(&id.to_string()) {
let tracked = &mut tracked.write().unwrap();
if let Conscrit {
ref mut blurred,
ref mut blur_codes,
..
} = tracked.state
{
if *blur_codes > 0 {
*blur_codes -= 1;
*blurred = true;
state_update(&tracked, &evt_queues, &admin_queue);
let track_clone = (*tracking).clone();
let queue_clone = (*evt_queues).clone();
let admin_clone = (*admin_queue).clone();
let id_str = id.to_string();
let timeout = Duration::from_millis(config.bonus_timeout);
tokio::spawn(async move {
sleep(timeout).await;
if let Conscrit {
ref mut blurred, ..
} = track_clone.get(&id_str).unwrap().write().unwrap().state
{
*blurred = false;
}
state_update(
&track_clone.get(&id_str).unwrap().read().unwrap(),
&queue_clone,
&admin_clone,
);
});
Status::Accepted
} else {
Status::PaymentRequired
}
} else {
Status::MethodNotAllowed
}
} else {
Status::BadRequest
}
}
pub fn routes() -> Vec<Route> {
routes![
store_pos,
tracked_view,
tracked_events,
set_state,
activate_invisibility,
activate_blur,
no_id,
]
}