Author:
Hash:
Timestamp:
+149 -140 +/-1 browse
Kevin Schoon [me@kevinschoon.com]
f2d54e635b0ad56859794529703c74c11392a25e
Wed, 10 Jan 2024 17:03:07 +0000 (1.3 years ago)
1 | diff --git a/src/web2/server.rs b/src/web2/server.rs |
2 | index 75ef234..e8cb16f 100644 |
3 | --- a/src/web2/server.rs |
4 | +++ b/src/web2/server.rs |
5 | @@ -4,11 +4,18 @@ use std::fs; |
6 | use std::net::SocketAddrV4; |
7 | use std::sync::Arc; |
8 | |
9 | - use axum::{body::Body, http::Request, middleware::from_fn_with_state, routing, Extension, Router}; |
10 | + use axum::{ |
11 | + body::Body, extract::Request, middleware::from_fn_with_state, routing, Extension, Router, |
12 | + ServiceExt, |
13 | + }; |
14 | use globwalk::glob_builder; |
15 | use tera::Tera; |
16 | use tokio::net::TcpListener; |
17 | - use tower_http::trace::{DefaultOnResponse, TraceLayer}; |
18 | + use tower::Layer; |
19 | + use tower_http::{ |
20 | + normalize_path::NormalizePathLayer, |
21 | + trace::{DefaultOnResponse, TraceLayer}, |
22 | + }; |
23 | use tracing::{Level, Span}; |
24 | |
25 | use crate::config::Config; |
26 | @@ -149,145 +156,147 @@ pub async fn serve(cfg: &Config) -> Result<(), Box<dyn Error>> { |
27 | let xmpp_required_plugins: &'static [rpc_initiator::Kind] = &[rpc_initiator::Kind::Xmpp]; |
28 | |
29 | let address: SocketAddrV4 = cfg.http.address.parse()?; |
30 | - let router = Router::new() |
31 | - .route("/robots.txt", routing::get(robots::serve)) |
32 | - .nest( |
33 | - "/", |
34 | - Router::new() |
35 | - .route("/", routing::get(index::index)) |
36 | - .route("/browse", routing::get(index::index)) |
37 | - .route("/:collection", routing::get(index::collection)) |
38 | - .route("/rss/firehose.xml", routing::get(rss::feed_firehose)) |
39 | - .route("/rss/1d.xml", routing::get(rss::feed_1d)) |
40 | - .route("/rss/1w.xml", routing::get(rss::feed_1w)) |
41 | - .route("/rss/1m.xml", routing::get(rss::feed_1m)) |
42 | - .route("/about", routing::get(about::serve)) |
43 | - .route("/config", routing::get(config::serve).post(config::update)) |
44 | - .layer(from_fn_with_state( |
45 | - Arc::new((cfg.clone(), templates.clone())), |
46 | - template::middleware, |
47 | - )), |
48 | - ) |
49 | - .nest( |
50 | - "/mail", |
51 | - Router::new() |
52 | - .route("/", routing::get(mail::lists)) |
53 | - .route("/:list_id", routing::get(mail::threads)) |
54 | - .route("/export/:list_id", routing::get(mail::export)) |
55 | - .route("/export/:list_id/:thread_id", routing::get(mail::export)) |
56 | - .route( |
57 | - "/export/:list_id/:thread_id/:message_id", |
58 | - routing::get(mail::export), |
59 | - ) |
60 | - .route("/thread/:list_id/:thread_id", routing::get(mail::thread)) |
61 | - .route("/message/:list_id/:message_id", routing::get(mail::message)) |
62 | - .layer(from_fn_with_state( |
63 | - Arc::new((cfg.clone(), templates.clone(), mail_required_plugins)), |
64 | - rpc_initiator::required, |
65 | - )) |
66 | - .layer(from_fn_with_state( |
67 | - Arc::new((cfg.clone(), templates.clone())), |
68 | - template::middleware, |
69 | - )), |
70 | - ) |
71 | - .nest( |
72 | - "/xmpp", |
73 | - Router::new() |
74 | - .route("/", routing::get(xmpp::channels)) |
75 | - .route("/:channel", routing::get(xmpp::channel)) |
76 | - .route("/:channel/:last_message", routing::get(xmpp::channel)) |
77 | - .layer(from_fn_with_state( |
78 | - Arc::new((cfg.clone(), templates.clone(), xmpp_required_plugins)), |
79 | - rpc_initiator::required, |
80 | - )) |
81 | - .layer(from_fn_with_state( |
82 | - Arc::new((cfg.clone(), templates.clone())), |
83 | - template::middleware, |
84 | - )), |
85 | - ) |
86 | - .nest( |
87 | - "/:collection/:name", |
88 | - Router::new() |
89 | - .route("/", routing::get(repo::serve)) |
90 | - .route( |
91 | - "/rss/firehose.xml", |
92 | - routing::get(rss::feed_repository_firehose), |
93 | - ) |
94 | - .route("/rss/1d.xml", routing::get(rss::feed_repository_1d)) |
95 | - .route("/rss/1w.xml", routing::get(rss::feed_repository_1w)) |
96 | - .route("/rss/1m.xml", routing::get(rss::feed_repository_1m)) |
97 | - .route("/commit/:commit_id", routing::get(commit::serve)) |
98 | - .route("/tree/:commitish", routing::get(repo::serve)) |
99 | - .route("/tree/:commitish/*file_path", routing::get(repo::serve)) |
100 | - .route("/log", routing::get(log_route::serve)) |
101 | - .route("/log/:commitish", routing::get(log_route::serve)) |
102 | - .route("/log/:commitish/*file_path", routing::get(log_route::serve)) |
103 | - .route("/charts", routing::get(chart::serve)) |
104 | - .route("/chart/:kind", routing::get(chart::serve)) |
105 | - .route("/chart/:kind/:commit_id", routing::get(chart::serve)) |
106 | - .route( |
107 | - "/:kind/:commit_id/:width/:height", |
108 | - routing::get(chart::serve), |
109 | - ) |
110 | - .route("/authors", routing::get(authors::serve)) |
111 | - .route("/blame/:commitish/*file_path", routing::get(blame::serve)) |
112 | - .route("/blob/:commitish/*file_path", routing::get(blob::serve)) |
113 | - .route("/raw/:commitish/*file_path", routing::get(blob::serve_raw)) |
114 | - .route("/builds", routing::get(builds::serve)) |
115 | - .route("/builds/badge/:commitish", routing::get(builds::badge)) |
116 | - .route("/builds/:commit_id", routing::get(builds::details)) |
117 | - .route( |
118 | - "/builds/:commit_id/:build_id", |
119 | - routing::get(builds::details), |
120 | - ) |
121 | - .route("/bugs", routing::get(bugs::bugs)) |
122 | - .route("/bugs/:bug_id", routing::get(bugs::bug)) |
123 | - .route("/refs", routing::get(refs::tags)) |
124 | - .route("/refs/branches", routing::get(refs::branches)) |
125 | - .route("/refs/tags", routing::get(refs::tags)) |
126 | - .route("/refs/archive/:ref_id", routing::get(refs::archive)) |
127 | - .layer(from_fn_with_state(cfg.clone(), repository::middleware)) |
128 | - .layer(from_fn_with_state( |
129 | - Arc::new(cfg.clone()), |
130 | - rpc_initiator::optional, |
131 | - )) |
132 | - .layer(from_fn_with_state( |
133 | - Arc::new((cfg.clone(), templates.clone())), |
134 | - template::middleware, |
135 | - )), |
136 | - ) |
137 | - .route( |
138 | - "/.well-known/webfinger", |
139 | - routing::get(finger::serve).layer(Extension(finger::CResolver { |
140 | - domain: "todo", |
141 | - config: Arc::new(cfg.clone()), |
142 | - })), |
143 | - ) |
144 | - .route("/static/main.min.css", routing::get(assets::serve_css)) |
145 | - .route("/static/assets/:asset", routing::get(assets::serve_asset)) |
146 | - .layer(Extension(cfg.clone())) |
147 | - .layer(Extension(Arc::new(db))) |
148 | - .layer(Extension(highlighter)) |
149 | - .layer(Extension(adapter)) |
150 | - // error handling |
151 | - .layer(from_fn_with_state( |
152 | - Arc::new((cfg.clone(), templates.clone())), |
153 | - error::middleware, |
154 | - )) |
155 | - // git hosted static sites |
156 | - .layer(from_fn_with_state( |
157 | - (cfg.clone(), site_mapping), |
158 | - sites::middleware, |
159 | - )) |
160 | - .layer( |
161 | - TraceLayer::new_for_http() |
162 | - .on_request(|request: &Request<Body>, _span: &Span| { |
163 | - tracing::info!("started {} {}", request.method(), request.uri().path()) |
164 | - }) |
165 | - .on_response(DefaultOnResponse::new().level(Level::INFO)), |
166 | - ); |
167 | + let app = NormalizePathLayer::trim_trailing_slash().layer( |
168 | + Router::new() |
169 | + .route("/robots.txt", routing::get(robots::serve)) |
170 | + .nest( |
171 | + "/", |
172 | + Router::new() |
173 | + .route("/", routing::get(index::index)) |
174 | + .route("/browse", routing::get(index::index)) |
175 | + .route("/:collection", routing::get(index::collection)) |
176 | + .route("/rss/firehose.xml", routing::get(rss::feed_firehose)) |
177 | + .route("/rss/1d.xml", routing::get(rss::feed_1d)) |
178 | + .route("/rss/1w.xml", routing::get(rss::feed_1w)) |
179 | + .route("/rss/1m.xml", routing::get(rss::feed_1m)) |
180 | + .route("/about", routing::get(about::serve)) |
181 | + .route("/config", routing::get(config::serve).post(config::update)) |
182 | + .layer(from_fn_with_state( |
183 | + Arc::new((cfg.clone(), templates.clone())), |
184 | + template::middleware, |
185 | + )), |
186 | + ) |
187 | + .nest( |
188 | + "/mail", |
189 | + Router::new() |
190 | + .route("/", routing::get(mail::lists)) |
191 | + .route("/:list_id", routing::get(mail::threads)) |
192 | + .route("/export/:list_id", routing::get(mail::export)) |
193 | + .route("/export/:list_id/:thread_id", routing::get(mail::export)) |
194 | + .route( |
195 | + "/export/:list_id/:thread_id/:message_id", |
196 | + routing::get(mail::export), |
197 | + ) |
198 | + .route("/thread/:list_id/:thread_id", routing::get(mail::thread)) |
199 | + .route("/message/:list_id/:message_id", routing::get(mail::message)) |
200 | + .layer(from_fn_with_state( |
201 | + Arc::new((cfg.clone(), templates.clone(), mail_required_plugins)), |
202 | + rpc_initiator::required, |
203 | + )) |
204 | + .layer(from_fn_with_state( |
205 | + Arc::new((cfg.clone(), templates.clone())), |
206 | + template::middleware, |
207 | + )), |
208 | + ) |
209 | + .nest( |
210 | + "/xmpp", |
211 | + Router::new() |
212 | + .route("/", routing::get(xmpp::channels)) |
213 | + .route("/:channel", routing::get(xmpp::channel)) |
214 | + .route("/:channel/:last_message", routing::get(xmpp::channel)) |
215 | + .layer(from_fn_with_state( |
216 | + Arc::new((cfg.clone(), templates.clone(), xmpp_required_plugins)), |
217 | + rpc_initiator::required, |
218 | + )) |
219 | + .layer(from_fn_with_state( |
220 | + Arc::new((cfg.clone(), templates.clone())), |
221 | + template::middleware, |
222 | + )), |
223 | + ) |
224 | + .nest( |
225 | + "/:collection/:name", |
226 | + Router::new() |
227 | + .route("/", routing::get(repo::serve)) |
228 | + .route( |
229 | + "/rss/firehose.xml", |
230 | + routing::get(rss::feed_repository_firehose), |
231 | + ) |
232 | + .route("/rss/1d.xml", routing::get(rss::feed_repository_1d)) |
233 | + .route("/rss/1w.xml", routing::get(rss::feed_repository_1w)) |
234 | + .route("/rss/1m.xml", routing::get(rss::feed_repository_1m)) |
235 | + .route("/commit/:commit_id", routing::get(commit::serve)) |
236 | + .route("/tree/:commitish", routing::get(repo::serve)) |
237 | + .route("/tree/:commitish/*file_path", routing::get(repo::serve)) |
238 | + .route("/log", routing::get(log_route::serve)) |
239 | + .route("/log/:commitish", routing::get(log_route::serve)) |
240 | + .route("/log/:commitish/*file_path", routing::get(log_route::serve)) |
241 | + .route("/charts", routing::get(chart::serve)) |
242 | + .route("/chart/:kind", routing::get(chart::serve)) |
243 | + .route("/chart/:kind/:commit_id", routing::get(chart::serve)) |
244 | + .route( |
245 | + "/:kind/:commit_id/:width/:height", |
246 | + routing::get(chart::serve), |
247 | + ) |
248 | + .route("/authors", routing::get(authors::serve)) |
249 | + .route("/blame/:commitish/*file_path", routing::get(blame::serve)) |
250 | + .route("/blob/:commitish/*file_path", routing::get(blob::serve)) |
251 | + .route("/raw/:commitish/*file_path", routing::get(blob::serve_raw)) |
252 | + .route("/builds", routing::get(builds::serve)) |
253 | + .route("/builds/badge/:commitish", routing::get(builds::badge)) |
254 | + .route("/builds/:commit_id", routing::get(builds::details)) |
255 | + .route( |
256 | + "/builds/:commit_id/:build_id", |
257 | + routing::get(builds::details), |
258 | + ) |
259 | + .route("/bugs", routing::get(bugs::bugs)) |
260 | + .route("/bugs/:bug_id", routing::get(bugs::bug)) |
261 | + .route("/refs", routing::get(refs::tags)) |
262 | + .route("/refs/branches", routing::get(refs::branches)) |
263 | + .route("/refs/tags", routing::get(refs::tags)) |
264 | + .route("/refs/archive/:ref_id", routing::get(refs::archive)) |
265 | + .layer(from_fn_with_state(cfg.clone(), repository::middleware)) |
266 | + .layer(from_fn_with_state( |
267 | + Arc::new(cfg.clone()), |
268 | + rpc_initiator::optional, |
269 | + )) |
270 | + .layer(from_fn_with_state( |
271 | + Arc::new((cfg.clone(), templates.clone())), |
272 | + template::middleware, |
273 | + )), |
274 | + ) |
275 | + .route( |
276 | + "/.well-known/webfinger", |
277 | + routing::get(finger::serve).layer(Extension(finger::CResolver { |
278 | + domain: "todo", |
279 | + config: Arc::new(cfg.clone()), |
280 | + })), |
281 | + ) |
282 | + .route("/static/main.min.css", routing::get(assets::serve_css)) |
283 | + .route("/static/assets/:asset", routing::get(assets::serve_asset)) |
284 | + .layer(Extension(cfg.clone())) |
285 | + .layer(Extension(Arc::new(db))) |
286 | + .layer(Extension(highlighter)) |
287 | + .layer(Extension(adapter)) |
288 | + // error handling |
289 | + .layer(from_fn_with_state( |
290 | + Arc::new((cfg.clone(), templates.clone())), |
291 | + error::middleware, |
292 | + )) |
293 | + // git hosted static sites |
294 | + .layer(from_fn_with_state( |
295 | + (cfg.clone(), site_mapping), |
296 | + sites::middleware, |
297 | + )) |
298 | + .layer( |
299 | + TraceLayer::new_for_http() |
300 | + .on_request(|request: &Request<Body>, _span: &Span| { |
301 | + tracing::info!("started {} {}", request.method(), request.uri().path()) |
302 | + }) |
303 | + .on_response(DefaultOnResponse::new().level(Level::INFO)), |
304 | + ), |
305 | + ); |
306 | log::info!("listening @ {}", cfg.http.address); |
307 | let listener = TcpListener::bind(address).await?; |
308 | - axum::serve(listener, router.into_make_service()).await?; |
309 | + axum::serve(listener, ServiceExt::<Request>::into_make_service(app)).await?; |
310 | Ok(()) |
311 | } |