atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0
545ad65826dde9afbbcd3f3c23f9f0c01b5adce8
1
ssh://brewery@pls.lobotomise.me:33/atagen/jelq.git

Blame: src/http/links.rs

8b8e83329a1datagen2026-10-12 12:01 UTC1
use std::fmt::Write as _;
8b8e83329a1datagen2026-10-12 12:01 UTC2
a11497af08aaatagen2026-10-13 12:04 UTC3
use super::{run::RunResource, runs};
a11497af08aaatagen2026-10-13 12:04 UTC4
use crate::game::{Branch, Run, SHOP};
8b8e83329a1datagen2026-10-12 12:01 UTC5
8b8e83329a1datagen2026-10-12 12:01 UTC6
pub const REL_BASE: &str = "https://jelq.dev/rels/";
8b8e83329a1datagen2026-10-12 12:01 UTC7
e028a4184d00atagen2026-10-14 10:49 UTC8
/// One RFC 8288 link. `allow`, `lubricant` and `intensity` are extension attributes (§3), so a client never
8b8e83329a1datagen2026-10-12 12:01 UTC9
/// has to guess what a target accepts.
8b8e83329a1datagen2026-10-12 12:01 UTC10
struct Link<'a> {
8b8e83329a1datagen2026-10-12 12:01 UTC11
    href: &'a str,
8b8e83329a1datagen2026-10-12 12:01 UTC12
    rel: &'a str,
8b8e83329a1datagen2026-10-12 12:01 UTC13
    allow: &'a str,
8b8e83329a1datagen2026-10-12 12:01 UTC14
    title: Option<&'a str>,
8b8e83329a1datagen2026-10-12 12:01 UTC15
    lubricant: Option<&'a str>,
e028a4184d00atagen2026-10-14 10:49 UTC16
    intensity: Option<&'a str>,
8b8e83329a1datagen2026-10-12 12:01 UTC17
}
8b8e83329a1datagen2026-10-12 12:01 UTC18
8b8e83329a1datagen2026-10-12 12:01 UTC19
impl Link<'_> {
8b8e83329a1datagen2026-10-12 12:01 UTC20
    fn write(&self, out: &mut String) {
8b8e83329a1datagen2026-10-12 12:01 UTC21
        if !out.is_empty() {
8b8e83329a1datagen2026-10-12 12:01 UTC22
            out.push_str(", ");
8b8e83329a1datagen2026-10-12 12:01 UTC23
        }
8b8e83329a1datagen2026-10-12 12:01 UTC24
        let _ = write!(out, "<{}>; rel=\"{REL_BASE}{}\"", self.href, self.rel);
8b8e83329a1datagen2026-10-12 12:01 UTC25
        if let Some(title) = self.title {
8b8e83329a1datagen2026-10-12 12:01 UTC26
            let _ = write!(out, "; title=\"{title}\"");
8b8e83329a1datagen2026-10-12 12:01 UTC27
        }
8b8e83329a1datagen2026-10-12 12:01 UTC28
        let _ = write!(out, "; allow=\"{}\"", self.allow);
8b8e83329a1datagen2026-10-12 12:01 UTC29
        if let Some(rule) = self.lubricant {
8b8e83329a1datagen2026-10-12 12:01 UTC30
            let _ = write!(out, "; lubricant=\"{rule}\"");
8b8e83329a1datagen2026-10-12 12:01 UTC31
        }
e028a4184d00atagen2026-10-14 10:49 UTC32
        if let Some(range) = self.intensity {
e028a4184d00atagen2026-10-14 10:49 UTC33
            let _ = write!(out, "; intensity=\"{range}\"");
e028a4184d00atagen2026-10-14 10:49 UTC34
        }
8b8e83329a1datagen2026-10-12 12:01 UTC35
    }
8b8e83329a1datagen2026-10-12 12:01 UTC36
}
8b8e83329a1datagen2026-10-12 12:01 UTC37
8b8e83329a1datagen2026-10-12 12:01 UTC38
pub fn header(run: &Run) -> String {
8b8e83329a1datagen2026-10-12 12:01 UTC39
    let reach = run.reach();
8b8e83329a1datagen2026-10-12 12:01 UTC40
    let mut out = String::new();
8b8e83329a1datagen2026-10-12 12:01 UTC41
    let resources: [(&str, &RunResource, bool); 15] = [
8b8e83329a1datagen2026-10-12 12:01 UTC42
        ("", &runs::RUN, true),
8b8e83329a1datagen2026-10-12 12:01 UTC43
        ("floor", &runs::FLOOR, true),
8b8e83329a1datagen2026-10-12 12:01 UTC44
        ("length", &runs::LENGTH, true),
8b8e83329a1datagen2026-10-12 12:01 UTC45
        ("foreskin", &runs::FORESKIN, reach.foreskin),
8b8e83329a1datagen2026-10-12 12:01 UTC46
        ("inventory", &runs::INVENTORY, true),
8b8e83329a1datagen2026-10-12 12:01 UTC47
        ("techniques", &runs::TECHNIQUES, true),
8b8e83329a1datagen2026-10-12 12:01 UTC48
        ("drawer", &runs::DRAWER, reach.drawer),
8b8e83329a1datagen2026-10-12 12:01 UTC49
        ("kitchen", &runs::KITCHEN, reach.kitchen),
a11497af08aaatagen2026-10-13 12:04 UTC50
        ("thread", &runs::THREAD, reach.thread),
8b8e83329a1datagen2026-10-12 12:01 UTC51
        ("grip", &runs::GRIP, true),
8b8e83329a1datagen2026-10-12 12:01 UTC52
        ("shop", &runs::SHOP, reach.shop),
8b8e83329a1datagen2026-10-12 12:01 UTC53
        ("portal", &runs::PORTAL, reach.portal),
8b8e83329a1datagen2026-10-12 12:01 UTC54
        ("elder", &runs::ELDER, reach.elder),
8b8e83329a1datagen2026-10-12 12:01 UTC55
        ("footage", &runs::FOOTAGE, reach.footage),
8b8e83329a1datagen2026-10-12 12:01 UTC56
        ("diagnosis", &runs::DIAGNOSIS, reach.diagnosis),
8b8e83329a1datagen2026-10-12 12:01 UTC57
    ];
8b8e83329a1datagen2026-10-12 12:01 UTC58
    for (rel, target, _) in resources.iter().filter(|(_, _, relevant)| *relevant) {
8b8e83329a1datagen2026-10-12 12:01 UTC59
        let href = if rel.is_empty() {
8b8e83329a1datagen2026-10-12 12:01 UTC60
            run.path("")
8b8e83329a1datagen2026-10-12 12:01 UTC61
        } else {
8b8e83329a1datagen2026-10-12 12:01 UTC62
            run.path(&format!("/{rel}"))
8b8e83329a1datagen2026-10-12 12:01 UTC63
        };
8b8e83329a1datagen2026-10-12 12:01 UTC64
        Link {
8b8e83329a1datagen2026-10-12 12:01 UTC65
            href: &href,
8b8e83329a1datagen2026-10-12 12:01 UTC66
            rel: if rel.is_empty() { "run" } else { rel },
8b8e83329a1datagen2026-10-12 12:01 UTC67
            allow: &target.resource.allow(run),
8b8e83329a1datagen2026-10-12 12:01 UTC68
            title: None,
8b8e83329a1datagen2026-10-12 12:01 UTC69
            lubricant: None,
e028a4184d00atagen2026-10-14 10:49 UTC70
            intensity: None,
8b8e83329a1datagen2026-10-12 12:01 UTC71
        }
8b8e83329a1datagen2026-10-12 12:01 UTC72
        .write(&mut out);
8b8e83329a1datagen2026-10-12 12:01 UTC73
    }
8b8e83329a1datagen2026-10-12 12:01 UTC74
    if reach.branch_pending {
8b8e83329a1datagen2026-10-12 12:01 UTC75
        for (branch, title) in [
8b8e83329a1datagen2026-10-12 12:01 UTC76
            (Branch::Forum, "Read the forum"),
8b8e83329a1datagen2026-10-12 12:01 UTC77
            (Branch::CloseTab, "Close the tab"),
8b8e83329a1datagen2026-10-12 12:01 UTC78
        ] {
8b8e83329a1datagen2026-10-12 12:01 UTC79
            Link {
8b8e83329a1datagen2026-10-12 12:01 UTC80
                href: &run.path(&format!("/branches/{}", branch.slug())),
8b8e83329a1datagen2026-10-12 12:01 UTC81
                rel: "branch",
8b8e83329a1datagen2026-10-12 12:01 UTC82
                allow: "POST",
8b8e83329a1datagen2026-10-12 12:01 UTC83
                title: Some(title),
8b8e83329a1datagen2026-10-12 12:01 UTC84
                lubricant: None,
e028a4184d00atagen2026-10-14 10:49 UTC85
                intensity: None,
8b8e83329a1datagen2026-10-12 12:01 UTC86
            }
8b8e83329a1datagen2026-10-12 12:01 UTC87
            .write(&mut out);
8b8e83329a1datagen2026-10-12 12:01 UTC88
        }
8b8e83329a1datagen2026-10-12 12:01 UTC89
    }
8b8e83329a1datagen2026-10-12 12:01 UTC90
    let run_path = run.path("");
8b8e83329a1datagen2026-10-12 12:01 UTC91
    for technique in run.techniques_now() {
8b8e83329a1datagen2026-10-12 12:01 UTC92
        let name = technique.name();
8b8e83329a1datagen2026-10-12 12:01 UTC93
        Link {
8b8e83329a1datagen2026-10-12 12:01 UTC94
            href: &format!("{run_path}?technique={name}"),
8b8e83329a1datagen2026-10-12 12:01 UTC95
            rel: "technique",
8b8e83329a1datagen2026-10-12 12:01 UTC96
            allow: "JELQ",
8b8e83329a1datagen2026-10-12 12:01 UTC97
            title: Some(name),
8b8e83329a1datagen2026-10-12 12:01 UTC98
            lubricant: technique.lubricant(),
e028a4184d00atagen2026-10-14 10:49 UTC99
            intensity: technique.intensity(),
8b8e83329a1datagen2026-10-12 12:01 UTC100
        }
8b8e83329a1datagen2026-10-12 12:01 UTC101
        .write(&mut out);
8b8e83329a1datagen2026-10-12 12:01 UTC102
    }
8b8e83329a1datagen2026-10-12 12:01 UTC103
    if reach.shopping {
8b8e83329a1datagen2026-10-12 12:01 UTC104
        for item in SHOP {
8b8e83329a1datagen2026-10-12 12:01 UTC105
            let Some(price) = run.price(item) else {
8b8e83329a1datagen2026-10-12 12:01 UTC106
                continue;
8b8e83329a1datagen2026-10-12 12:01 UTC107
            };
8b8e83329a1datagen2026-10-12 12:01 UTC108
            Link {
8b8e83329a1datagen2026-10-12 12:01 UTC109
                href: &run.path(&format!("/shop/{}", item.slug())),
8b8e83329a1datagen2026-10-12 12:01 UTC110
                rel: "shop-item",
8b8e83329a1datagen2026-10-12 12:01 UTC111
                allow: "POST",
8b8e83329a1datagen2026-10-12 12:01 UTC112
                title: Some(&format!("{} for {price}", item.slug())),
8b8e83329a1datagen2026-10-12 12:01 UTC113
                lubricant: None,
e028a4184d00atagen2026-10-14 10:49 UTC114
                intensity: None,
8b8e83329a1datagen2026-10-12 12:01 UTC115
            }
8b8e83329a1datagen2026-10-12 12:01 UTC116
            .write(&mut out);
8b8e83329a1datagen2026-10-12 12:01 UTC117
        }
8b8e83329a1datagen2026-10-12 12:01 UTC118
    }
8b8e83329a1datagen2026-10-12 12:01 UTC119
    out
8b8e83329a1datagen2026-10-12 12:01 UTC120
}