atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
058650ec79d6eb6841ce768ab49335ed74ae8b97
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git
src/game/clinic.rsRust85 lines3.0 KB
1
use axum::http::{StatusCode, header};
2
use serde_json::json;
3
4
use super::{Floor, Outcome, Run, etag_matches, parse_credentials, round2};
5
use crate::{
6
    headers::{SERVER_TIMING, X_DIAGNOSIS},
7
    problem::Problem,
8
};
9
10
const INTAKE: [&str; 3] = [
11
    "The clinic does not accept excuses.",
12
    "The clinic accepts one token. You have not been carrying it.",
13
    "Be honest.",
14
];
15
16
impl Run {
17
    pub fn diagnose(
18
        &mut self,
19
        authorization: Option<&str>,
20
        if_none_match: Option<&str>,
21
    ) -> Result<Outcome, Problem> {
22
        if self.floor != Floor::Clinic {
23
            let floors = Floor::Clinic.number() - self.floor.number();
24
            return Err(Problem::new(
25
                StatusCode::TOO_EARLY,
26
                "no-appointment",
27
                format!("The clinic's next available appointment is {floors} floors away."),
28
            ));
29
        }
30
        let intake = Problem::new(
31
            StatusCode::UNAUTHORIZED,
32
            "intake",
33
            "The clinic requires authorisation.",
34
        );
35
        let Some(authorization) = authorization else {
36
            return Err(intake.header(header::WWW_AUTHENTICATE, "Bearer realm=\"clinic\""));
37
        };
38
        let truthful = parse_credentials(authorization, "bearer")
39
            .is_some_and(|token| token.eq_ignore_ascii_case("honesty"));
40
        if !truthful {
41
            let hint = INTAKE[self.clinic.intake_attempts.min(INTAKE.len() - 1)];
42
            self.clinic.intake_attempts += 1;
43
            return Err(intake.header(
44
                header::WWW_AUTHENTICATE,
45
                format!(
46
                    "Bearer realm=\"clinic\", error=\"invalid_token\", error_description=\"{hint}\""
47
                ),
48
            ));
49
        }
50
51
        self.conditions.peyronie = false;
52
        self.conditions.priapism_turns = 0;
53
        let etag = self.origin_etag();
54
        if if_none_match.is_some_and(|inm| etag_matches(inm, &etag)) {
55
            self.clinic.cured = true;
56
            return Ok(Outcome::empty(StatusCode::NOT_MODIFIED)
57
                .header(header::ETAG, etag)
58
                .header(X_DIAGNOSIS, "normal"));
59
        }
60
        if !self.clinic.measured {
61
            self.clinic.measured = true;
62
            if !self.items.ruler {
63
                self.shame += 15;
64
            }
65
        }
66
        let volume = self.volume(self.length);
67
        let foreskin = self.foreskin.unwrap_or(0.0);
68
        let timing = format!(
69
            "length;dur={:.2}, girth;dur={:.2}, foreskin;dur={foreskin:.2}, volume;desc=\"cubic inches\";dur={volume:.2}",
70
            self.length, self.girth
71
        );
72
        Ok(Outcome::json(
73
            StatusCode::OK,
74
            json!({
75
                "diagnosis": "within normal range",
76
                "measured_length": round2(self.length),
77
                "measured_girth": round2(self.girth),
78
                "volume": round2(volume),
79
                "prescription": "Please stop.",
80
            }),
81
        )
82
        .header(header::ETAG, etag)
83
        .header(SERVER_TIMING, timing))
84
    }
85
}