refactor: Split web code into multiple files, improve static resource loading

This commit is contained in:
Ginger 2026-02-28 20:32:46 -05:00
parent 9515019641
commit 3d50af0943
No known key found for this signature in database
14 changed files with 194 additions and 65 deletions

76
Cargo.lock generated
View file

@ -1170,8 +1170,10 @@ dependencies = [
"conduwuit_build_metadata", "conduwuit_build_metadata",
"conduwuit_service", "conduwuit_service",
"futures", "futures",
"memory-serve",
"rand 0.10.0", "rand 0.10.0",
"thiserror 2.0.18", "thiserror 2.0.18",
"tower-http",
"tracing", "tracing",
] ]
@ -3027,6 +3029,22 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "memory-serve"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81b5bbad2035f57b1e95f66da606832edd935b47d82312e38e1ccffbcfb8a427"
dependencies = [
"axum",
"brotli",
"flate2",
"mime_guess",
"sha256",
"tracing",
"urlencoding",
"walkdir",
]
[[package]] [[package]]
name = "meowlnir-antispam" name = "meowlnir-antispam"
version = "0.1.0" version = "0.1.0"
@ -3043,6 +3061,16 @@ version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
[[package]]
name = "mime_guess"
version = "2.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
dependencies = [
"mime",
"unicase",
]
[[package]] [[package]]
name = "minicbor" name = "minicbor"
version = "2.2.1" version = "2.2.1"
@ -4632,6 +4660,15 @@ version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "sanitize-filename" name = "sanitize-filename"
version = "0.6.0" version = "0.6.0"
@ -4993,6 +5030,19 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sha256"
version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f880fc8562bdeb709793f00eb42a2ad0e672c4f883bbe59122b926eca935c8f6"
dependencies = [
"async-trait",
"bytes",
"hex",
"sha2",
"tokio",
]
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.7" version = "0.1.7"
@ -5673,6 +5723,7 @@ version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [ dependencies = [
"log",
"pin-project-lite", "pin-project-lite",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
@ -5894,6 +5945,12 @@ dependencies = [
"serde_derive", "serde_derive",
] ]
[[package]]
name = "urlencoding"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da"
[[package]] [[package]]
name = "utf-8" name = "utf-8"
version = "0.7.6" version = "0.7.6"
@ -5947,6 +6004,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
@ -6161,6 +6228,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys 0.61.2",
]
[[package]] [[package]]
name = "winapi-x86_64-pc-windows-gnu" name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0" version = "0.4.0"

View file

@ -26,6 +26,11 @@ futures.workspace = true
tracing.workspace = true tracing.workspace = true
rand.workspace = true rand.workspace = true
thiserror.workspace = true thiserror.workspace = true
tower-http.workspace = true
memory-serve = "2.1.0"
[build-dependencies]
memory-serve = "2.1.0"
[lints] [lints]
workspace = true workspace = true

2
src/web/askama.toml Normal file
View file

@ -0,0 +1,2 @@
[general]
dirs = ["pages/templates"]

1
src/web/build.rs Normal file
View file

@ -0,0 +1 @@
fn main() { memory_serve::load_directory("./pages/resources"); }

View file

@ -1,52 +1,15 @@
use askama::Template; use askama::Template;
use axum::{ use axum::{
Router, Router,
extract::State, http::{HeaderValue, StatusCode, header},
http::{StatusCode, header},
response::{Html, IntoResponse, Response}, response::{Html, IntoResponse, Response},
routing::get,
}; };
use conduwuit_build_metadata::{GIT_REMOTE_COMMIT_URL, GIT_REMOTE_WEB_URL, version_tag};
use conduwuit_service::state; use conduwuit_service::state;
use tower_http::set_header::SetResponseHeaderLayer;
pub fn build() -> Router<state::State> { mod pages;
Router::<state::State>::new()
.route("/", get(index_handler))
.route("/_continuwuity/logo.svg", get(logo_handler))
}
async fn index_handler( type State = state::State;
State(services): State<state::State>,
) -> Result<impl IntoResponse, WebError> {
#[derive(Debug, Template)]
#[template(path = "index.html.j2")]
struct Index<'a> {
nonce: &'a str,
server_name: &'a str,
first_run: bool,
}
let nonce = rand::random::<u64>().to_string();
let template = Index {
nonce: &nonce,
server_name: services.config.server_name.as_str(),
first_run: services.firstrun.is_first_run(),
};
Ok((
[(
header::CONTENT_SECURITY_POLICY,
format!("default-src 'nonce-{nonce}'; img-src 'self';"),
)],
Html(template.render()?),
))
}
async fn logo_handler() -> impl IntoResponse {
(
[(header::CONTENT_TYPE, "image/svg+xml")],
include_str!("templates/logo.svg").to_owned(),
)
}
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
enum WebError { enum WebError {
@ -58,29 +21,33 @@ impl IntoResponse for WebError {
fn into_response(self) -> Response { fn into_response(self) -> Response {
#[derive(Debug, Template)] #[derive(Debug, Template)]
#[template(path = "error.html.j2")] #[template(path = "error.html.j2")]
struct Error<'a> { struct Error {
nonce: &'a str,
err: WebError, err: WebError,
} }
let nonce = rand::random::<u64>().to_string();
let status = match &self { let status = match &self {
| Self::Render(_) => StatusCode::INTERNAL_SERVER_ERROR, | Self::Render(_) => StatusCode::INTERNAL_SERVER_ERROR,
}; };
let tmpl = Error { nonce: &nonce, err: self };
let tmpl = Error { err: self };
if let Ok(body) = tmpl.render() { if let Ok(body) = tmpl.render() {
( (status, Html(body)).into_response()
status,
[(
header::CONTENT_SECURITY_POLICY,
format!("default-src 'none' 'nonce-{nonce}';"),
)],
Html(body),
)
.into_response()
} else { } else {
(status, "Something went wrong").into_response() (status, "Something went wrong").into_response()
} }
} }
} }
pub fn build() -> Router<state::State> {
#[allow(clippy::wildcard_imports)]
use pages::*;
Router::new()
.merge(index::build())
.merge(resources::build())
.layer(SetResponseHeaderLayer::if_not_present(
header::CONTENT_SECURITY_POLICY,
HeaderValue::from_static("default-src 'self'"),
))
}

29
src/web/pages/index.rs Normal file
View file

@ -0,0 +1,29 @@
use askama::Template;
use axum::{
Router,
extract::State,
response::{Html, IntoResponse},
routing::get,
};
use conduwuit_service::state;
use crate::WebError;
pub(crate) fn build() -> Router<state::State> { Router::new().route("/", get(index_handler)) }
async fn index_handler(
State(services): State<state::State>,
) -> Result<impl IntoResponse, WebError> {
#[derive(Debug, Template)]
#[template(path = "index.html.j2")]
struct Index<'a> {
server_name: &'a str,
first_run: bool,
}
let template = Index {
server_name: services.config.server_name.as_str(),
first_run: services.firstrun.is_first_run(),
};
Ok(Html(template.render()?))
}

2
src/web/pages/mod.rs Normal file
View file

@ -0,0 +1,2 @@
pub(super) mod index;
pub(super) mod resources;

View file

@ -0,0 +1,9 @@
use axum::Router;
pub(crate) fn build() -> Router<crate::State> {
Router::new().nest(
"/_continuwuity/resources/",
#[allow(unused_qualifications)]
memory_serve::load!().index_file(None).into_router(),
)
}

View file

@ -0,0 +1,43 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="447.99823"
height="447.99823"
viewBox="0 0 447.99823 447.99823"
version="1.1"
id="svg1"
xml:space="preserve"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs
id="defs1" /><g
id="layer1"
transform="translate(-32.000893,-32.000893)"><circle
style="fill:#9b4bd4;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-dasharray:none;stroke-opacity:1"
id="path1"
cy="256"
cx="256"
r="176" /><path
style="fill:#de6cd3;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 41,174 69,36 C 135,126 175,102 226,94 l -12,31 62,-44 -69,-44 15,30 C 128,69 84,109 41,172 Z"
id="path7" /><path
style="fill:#de6cd3;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 338,41 -36,69 c 84,25 108,65 116,116 l -31,-12 44,62 44,-69 -30,15 C 443,128 403,84 340,41 Z"
id="path6" /><path
style="fill:#de6cd3;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 471,338 -69,-36 c -25,84 -65,108 -116,116 l 12,-31 -62,44 69,44 -15,-30 c 94,-2 138,-42 181,-105 z"
id="path8" /><path
style="fill:#de6cd3;fill-opacity:1;stroke:#000000;stroke-width:10;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1"
d="m 174,471 36,-69 C 126,377 102,337 94,286 l 31,12 -44,-62 -44,69 30,-15 c 2,94 42,138 105,181 z"
id="path9" /><g
id="g15"
transform="translate(-5.4157688e-4)"><path
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
d="m 155.45977,224.65379 c -7.25909,13.49567 -7.25909,26.09161 -6.35171,39.58729 0.90737,11.69626 12.7034,24.29222 24.49943,26.09164 21.77727,3.59884 28.12898,-20.69338 28.12898,-20.69338 0,0 4.53693,-15.29508 5.4443,-40.48699"
id="path11" /><path
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
d="m 218.96706,278.05399 c 3.00446,17.12023 7.52704,24.88918 19.22704,28.48918 9,2.7 22.5,-4.5 22.5,-16.2 0.9,21.6 17.1,17.1 19.8,17.1 11.7,-1.8 18.9,-14.4 16.2,-30.6"
id="path12" /><path
style="fill:none;stroke:#000000;stroke-width:10;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:normal"
d="m 305.6941,230.94317 c 1.8,27 6.3,40.5 6.3,40.5 8.1,27 28.8,19.8 28.8,19.8 18.9,-7.2 22.5,-24.3 22.5,-30.6 0,-25.2 -6.3,-35.1 -6.3,-35.1"
id="path13" /></g></g></svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -6,22 +6,18 @@
<title>{% block title %}Continuwuity{% endblock %}</title> <title>{% block title %}Continuwuity{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/_continuwuity/logo.svg"> <link rel="icon" href="/_continuwuity/resources/logo.svg">
<style type="text/css" nonce="{{ nonce }}"> <link rel="stylesheet" href="/_continuwuity/resources/style.css">
/*<![CDATA[*/
{{ include_str !("css/index.css") | safe }}
/*]]>*/
</style>
</head> </head>
<body> <body>
<main>{%~ block content %}{% endblock ~%}</main> <main>{%~ block content %}{% endblock ~%}</main>
{%~ block footer ~%} {%~ block footer ~%}
<footer> <footer>
<img class="logo" src="/_continuwuity/logo.svg"> <img class="logo" src="/_continuwuity/resources/logo.svg">
<p>Powered by <a href="https://continuwuity.org">Continuwuity</a> {{ env!("CARGO_PKG_VERSION") }} <p>Powered by <a href="https://continuwuity.org">Continuwuity</a> {{ env!("CARGO_PKG_VERSION") }}
{%~ if let Some(version_info) = self::version_tag() ~%} {%~ if let Some(version_info) = conduwuit_build_metadata::version_tag() ~%}
{%~ if let Some(url) = GIT_REMOTE_COMMIT_URL.or(GIT_REMOTE_WEB_URL) ~%} {%~ if let Some(url) = conduwuit_build_metadata::GIT_REMOTE_COMMIT_URL.or(conduwuit_build_metadata::GIT_REMOTE_WEB_URL) ~%}
(<a href="{{ url }}">{{ version_info }}</a>) (<a href="{{ url }}">{{ version_info }}</a>)
{%~ else ~%} {%~ else ~%}
({{ version_info }}) ({{ version_info }})

View file

@ -1 +0,0 @@
../../../docs/public/assets/logo.svg