an http based roguelike rpg about jelqing
Commit 7288fc269bb6
tarball5 files changed+56-6
@@ -67,6 +67,12 @@ dependencies = [
6767
]6868
6969
[[package]]70
+name = "bitflags"71
+version = "2.13.2"72
+source = "registry+https://github.com/rust-lang/crates.io-index"73
+checksum = "3ded4057c258ba199e2d26386d3af3780957ecaee6c4ef4041c6b4b8b97c0b06"74
+75
+[[package]]7076
name = "block-buffer"7177
version = "0.10.4"7278
source = "registry+https://github.com/rust-lang/crates.io-index"@@ -315,6 +321,7 @@ dependencies = [
315321
"sha2",316322
"tokio",317323
"tower",324
+ "tower-http",318325
]319326
320327
[[package]]@@ -636,6 +643,24 @@ dependencies = [
636643
]637644
638645
[[package]]646
+name = "tower-http"647
+version = "0.6.11"648
+source = "registry+https://github.com/rust-lang/crates.io-index"649
+checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840"650
+dependencies = [651
+ "bitflags",652
+ "bytes",653
+ "futures-util",654
+ "http",655
+ "http-body",656
+ "http-body-util",657
+ "pin-project-lite",658
+ "tower-layer",659
+ "tower-service",660
+ "tracing",661
+]662
+663
+[[package]]639664
name = "tower-layer"640665
version = "0.3.3"641666
source = "registry+https://github.com/rust-lang/crates.io-index"@@ -19,4 +19,5 @@ serde_json = "1"
1919
sha2 = "0.10"2020
tokio = { version = "1", features = ["io-util", "macros", "net", "rt-multi-thread"] }2121
tower = { version = "0.5", features = ["util"] }22
+tower-http = { version = "0.6", features = ["catch-panic"] }2223
@@ -156,3 +156,13 @@ pub async fn chrome(request: Request, next: Next) -> Response {
156156
.or_insert(HeaderValue::from_static("no-store, private"));157157
response158158
}159
+160
+/// A handler panic would otherwise drop the connection with no reply at all.161
+pub fn panicked(_: Box<dyn std::any::Any + Send + 'static>) -> Response {162
+ Problem::new(163
+ StatusCode::INTERNAL_SERVER_ERROR,164
+ "server-fault",165
+ "The server has had an internal event of its own. It is not discussing it.",166
+ )167
+ .into_response()168
+}@@ -19,6 +19,8 @@ use axum::{
1919
routing::{MethodRouter, any},2020
};2121
22
+use tower_http::catch_panic::CatchPanicLayer;23
+2224
use crate::{config::Config, game::Run};2325
use ctx::Ctx;2426
use resource::Resource;@@ -68,6 +70,7 @@ pub fn router(state: Shared) -> Router {
6870
.route("/ui/send", any(ui::send))6971
.with_state(api.clone());7072
api.merge(ui)73
+ .layer(CatchPanicLayer::custom(middleware::panicked))7174
}7275
7376
fn global(resource: &'static Resource<Shared>) -> MethodRouter<Shared> {@@ -109,5 +112,6 @@ fn api(state: Shared) -> Router {
109112
.route("/leaderboard", global(&meta::LEADERBOARD))110113
.fallback(meta::not_found)111114
.layer(axum::middleware::from_fn(middleware::chrome))115
+ .layer(CatchPanicLayer::custom(middleware::panicked))112116
.with_state(state)113117
}@@ -402,12 +402,22 @@ async function go(event) {
402402
log("> " + method + " " + short(path));403403
for (const [name, v] of headers) log("> " + name + ": " + v);404404
headers.push(["Accept-Language", $("locale").value]);405
- const response = await fetch("/ui/send", {406
- method: "POST",407
- headers: { "Content-Type": "application/json" },408
- body: JSON.stringify({ method, path, headers, body }),409
- });410
- const r = await response.json();405
+ let r;406
+ try {407
+ const response = await fetch("/ui/send", {408
+ method: "POST",409
+ headers: { "Content-Type": "application/json" },410
+ body: JSON.stringify({ method, path, headers, body }),411
+ });412
+ r = await response.json();413
+ } catch (error) {414
+ log("! The server did not answer. Is jelqd still running? (" + error.message + ")\n");415
+ return;416
+ }417
+ if (!Array.isArray(r.headers)) {418
+ log("! The page could not read that reply:\n " + JSON.stringify(r) + "\n");419
+ return;420
+ }411421
log(describe(r) + "\n");412422
absorb(r, method, path);413423
}