custom errors

This commit is contained in:
catvayor 2024-06-17 09:51:44 +02:00
parent 6dd6e46aab
commit bf9d82ed9f
25 changed files with 414 additions and 114 deletions

61
Cargo.lock generated
View file

@ -122,6 +122,16 @@ dependencies = [
"generic-array",
]
[[package]]
name = "bstr"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "bytemuck"
version = "1.16.0"
@ -432,6 +442,19 @@ version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "globset"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1"
dependencies = [
"aho-corasick",
"bstr",
"log",
"regex-automata 0.4.6",
"regex-syntax 0.8.3",
]
[[package]]
name = "h2"
version = "0.3.26"
@ -1154,6 +1177,41 @@ dependencies = [
"uncased",
]
[[package]]
name = "rust-embed"
version = "8.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a"
dependencies = [
"rust-embed-impl",
"rust-embed-utils",
"walkdir",
]
[[package]]
name = "rust-embed-impl"
version = "8.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4"
dependencies = [
"proc-macro2",
"quote",
"rust-embed-utils",
"syn",
"walkdir",
]
[[package]]
name = "rust-embed-utils"
version = "8.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32"
dependencies = [
"globset",
"sha2",
"walkdir",
]
[[package]]
name = "rustc-demangle"
version = "0.1.24"
@ -1564,11 +1622,12 @@ dependencies = [
[[package]]
name = "traque"
version = "0.1.0"
version = "0.2.4"
dependencies = [
"rand",
"rocket",
"rocket_dyn_templates",
"rust-embed",
]
[[package]]

View file

@ -1,6 +1,6 @@
[package]
name = "traque"
version = "0.1.0"
version = "0.2.4"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@ -8,6 +8,10 @@ edition = "2021"
[dependencies]
rand = "0.8.5"
[dependencies.rust-embed]
version = "8.4.0"
features = ["include-exclude"]
[dependencies.rocket]
version = "0.5.0"
features = ["json"]

View file

@ -3,13 +3,16 @@ extern crate rocket;
use rocket::{
fairing::AdHoc,
fs::{relative, FileServer},
response::stream::Event,
http::Status,
response::{content, stream::Event},
tokio::{
self, select,
time::{self, Duration},
},
Request,
};
use rocket_dyn_templates::Template;
use rust_embed::Embed;
use std::{
collections::VecDeque,
sync::{Arc, RwLock},
@ -68,6 +71,27 @@ fn clean_expired_evt(
}
}
#[derive(Embed)]
#[folder = "static/errors"]
#[include = "*.html"]
#[exclude = "*.jpg"]
struct ErrorPages;
#[catch(default)]
fn handler(status: Status, _: &Request) -> content::RawHtml<String> {
content::RawHtml(
std::str::from_utf8(
ErrorPages::get(format!("{}.html", status.code).as_str())
//501 not implemented
.unwrap_or(ErrorPages::get("501.html").unwrap())
.data
.as_ref(),
)
.unwrap()
.to_string(),
)
}
#[launch]
async fn rocket() -> _ {
let rocket = rocket::build();
@ -106,7 +130,8 @@ async fn rocket() -> _ {
.manage(admin_evt_queue.clone())
.mount("/", routes![index])
.mount("/track", track::routes())
.mount("/admin", admin::routes());
.mount("/admin", admin::routes())
.register("/", catchers![handler]);
if config.serve_static {
rocket = rocket.mount("/", FileServer::from(relative!("static")));
}

View file

@ -1,4 +1,5 @@
use rocket::{
http::Status,
response::stream::{Event, EventStream},
tokio::{
self, select,
@ -10,15 +11,20 @@ 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>,
) -> Option<Template> {
) -> Result<Template, Status> {
if let Some(tracked) = tracking.get(&id.to_string()) {
Some(Template::render(
Ok(Template::render(
match tracked.read().unwrap().state {
Vieux { .. } => "vieux",
Conscrit { .. } => "conscrit",
@ -31,7 +37,7 @@ fn tracked_view(
},
))
} else {
None
Err(Status::BadRequest)
}
}
@ -41,10 +47,10 @@ fn tracked_events<'a>(
evt_queue: &'a State<TrackingEventQueue>,
config: &State<Config>,
mut shutdown: Shutdown,
) -> Option<EventStream![Event + 'a]> {
) -> Result<EventStream![Event + 'a], Status> {
if evt_queue.contains_key(&id.to_string()) {
let timeout = Duration::from_millis(config.event_timeout);
Some(EventStream! {
Ok(EventStream! {
let mut interval = time::interval(timeout);
loop {
select!{
@ -59,7 +65,7 @@ fn tracked_events<'a>(
}
})
} else {
None
Err(Status::BadRequest)
}
}
@ -71,10 +77,13 @@ fn store_pos(
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
}
}
@ -86,19 +95,23 @@ fn set_state(
tracking: &State<Tracking>,
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
) -> Option<()> {
let tracked = &mut tracking.get(&id.to_string()).unwrap().write().unwrap();
if let Vieux {
ref mut invisible,
ref mut color,
} = tracked.state
{
*invisible = inv;
*color = col;
state_update(&tracked, &evt_queues, &admin_queue);
Some(())
) -> 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 {
None
Status::BadRequest
}
}
@ -109,43 +122,47 @@ pub async fn activate_invisibility(
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
config: &State<Config>,
) -> Option<()> {
let tracked = &mut tracking.get(&id.to_string()).unwrap().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,
);
});
Some(())
) -> 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 {
None
Status::MethodNotAllowed
}
} else {
None
Status::BadRequest
}
}
@ -156,43 +173,47 @@ pub async fn activate_blur(
evt_queues: &State<TrackingEventQueue>,
admin_queue: &State<AdminEventQueue>,
config: &State<Config>,
) -> Option<()> {
let tracked = &mut tracking.get(&id.to_string()).unwrap().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,
);
});
Some(())
) -> 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 {
None
Status::MethodNotAllowed
}
} else {
None
Status::BadRequest
}
}
@ -204,5 +225,6 @@ pub fn routes() -> Vec<Route> {
set_state,
activate_invisibility,
activate_blur,
no_id,
]
}

19
static/errors/400.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>400 Bad Request</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>400 Bad Request</h1>
<img src="/errors/cat/400.jpg"/>
<p>Conscrit ! Cet identifiant ne correspond à aucune équipe.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/401.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>401 Unauthorized</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>401 Unauthorized</h1>
<img src="/errors/cat/401.jpg"/>
<p>Il faut s'identifié pour accéder à cette ressource.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/402.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>402 Payment Required</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>402 Payment Required</h1>
<img src="/errors/cat/402.jpg"/>
<p>Toute les utilisations de ce bonus ont été utilisées.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/404.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>404 Not Found</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>404 Not Found</h1>
<img src="/errors/cat/404.jpg"/>
<p>Page non trouvé</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/405.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>405 Method Not Allowed</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>405 Method Not Allowed</h1>
<img src="/errors/cat/405.jpg"/>
<p>Cette équipe n'a pas le droit d'utiliser cet endpoint.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/418.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>418 Im a teapot</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>418 Im a teapot</h1>
<img src="/errors/cat/418.jpg"/>
<p>Il y a quelque-chose ici, mais je montrerai rien.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/498.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>498 Token expired/invalid</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>498 Token expired/invalid</h1>
<img src="/errors/cat/498.jpg"/>
<p>Le token d'authentification est invalide.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/500.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>500 Internal Server Error</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>500 Internal Server Error</h1>
<img src="/errors/cat/500.jpg"/>
<p>Erreur Interne</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/501.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>501 Not Implemented</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>501 Not Implemented</h1>
<img src="/errors/cat/501.jpg"/>
<p>Une erreur inconnue a été rencontré.</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

19
static/errors/503.html Normal file
View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>503 Service Unavailable</title>
</head>
<body align="center">
<div role="main" align="center">
<h1>503 Service Unavailable</h1>
<img src="/errors/cat/503.jpg"/>
<p>La traque n'est pas encore prête, on arrive bientôt...</p>
<hr />
</div>
<div role="contentinfo" align="center">
<small>Crédit à <a href="https://http.cat">http.cat</a> pour l'image.</small>
</div>
</body>
</html>

BIN
static/errors/cat/400.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
static/errors/cat/401.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
static/errors/cat/402.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
static/errors/cat/404.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
static/errors/cat/405.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
static/errors/cat/418.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
static/errors/cat/498.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

BIN
static/errors/cat/500.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
static/errors/cat/501.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
static/errors/cat/503.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -45,30 +45,30 @@
<body>
<div id="map"></div>
<div id="right">
<div class="tableFixHead">
<table>
<thead><tr>
<th>Nom</th>
<th>Mallette</th>
<th>Tracker</th>
<th>Invisible</th>
<th>Brouillé</th>
<th>Code Invisibilité</th>
<th>Code Brouillage</th>
<th>Couleur</th>
<!-- <th>Last Update</th> -->
</tr></thead>
<tbody id="teamInfos">
</tbody>
</table>
</div>
<div id="right">
<div class="tableFixHead">
<table>
<thead><tr>
<th>Nom</th>
<th>Mallette</th>
<th>Tracker</th>
<th>Invisible</th>
<th>Brouillé</th>
<th>Code Invisibilité</th>
<th>Code Brouillage</th>
<th>Couleur</th>
<!-- <th>Last Update</th> -->
</tr></thead>
<tbody id="teamInfos">
</tbody>
</table>
</div>
<input id="popup"/><button id="sendPopup">Send popup to all clients</button><br/>
<br/>
<a href="https://dgnum.eu"><img src="/dgnum-logo.png" height=50px /></a><br/>
<span style="font-size: 0.8em">Merci à la <a href="https://dgnum.eu">Délégation Générale NUMérique de l'ENS</a>, qui héberge ce site.</span>
</div>
<input id="popup"/><button id="sendPopup">Send popup to all clients</button><br/>
<br/>
<a href="https://dgnum.eu"><img src="/dgnum-logo.png" height=50px /></a><br/>
<span style="font-size: 0.8em">Merci à la <a href="https://dgnum.eu">Délégation Générale NUMérique de l'ENS</a>, qui héberge ce site.</span>
</div>
<script type="text/javascript">
setup_map();