Skip to content

Commit d05241b

Browse files
committed
migrate releases_handler to axum
1 parent 18c92fa commit d05241b

File tree

3 files changed

+104
-69
lines changed

3 files changed

+104
-69
lines changed

src/web/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ impl IntoResponse for AxumNope {
234234
}
235235
}
236236

237+
pub(crate) type WebResult<T> = Result<T, AxumNope>;
238+
237239
#[cfg(test)]
238240
mod tests {
239241
use crate::test::wrapper;

src/web/releases.rs

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,34 @@ use crate::{
44
build_queue::QueuedCrate,
55
cdn::{self, CrateInvalidation},
66
db::{Pool, PoolClient},
7-
impl_webpage,
7+
impl_axum_webpage, impl_webpage,
88
utils::report_error,
9-
web::{error::Nope, match_version, page::WebPage, parse_url_with_params, redirect_base},
9+
web::{
10+
error::{Nope, WebResult},
11+
match_version,
12+
page::WebPage,
13+
parse_url_with_params, redirect_base,
14+
},
1015
BuildQueue, Config,
1116
};
12-
use anyhow::{anyhow, Result};
17+
use anyhow::{anyhow, Context as _, Result};
18+
use axum::{
19+
extract::{Extension, Path},
20+
response::IntoResponse,
21+
};
1322
use chrono::{DateTime, NaiveDate, Utc};
1423
use iron::{
1524
headers::{ContentType, Expires, HttpDate},
1625
mime::{Mime, SubLevel, TopLevel},
1726
modifiers::Redirect,
18-
status, IronError, IronResult, Request, Response, Url,
27+
status, IronError, IronResult, Request, Response as IronResponse, Url,
1928
};
2029
use postgres::Client;
2130
use router::Router;
2231
use serde::{Deserialize, Serialize};
2332
use std::collections::{BTreeMap, HashMap};
2433
use std::str;
34+
use tokio::task::spawn_blocking;
2535
use tracing::{debug, warn};
2636
use url::form_urlencoded;
2737

@@ -63,7 +73,7 @@ pub(crate) fn get_releases(
6373
limit: i64,
6474
order: Order,
6575
latest_only: bool,
66-
) -> Vec<Release> {
76+
) -> Result<Vec<Release>> {
6777
let offset = (page - 1) * limit;
6878

6979
// WARNING: it is _crucial_ that this always be hard-coded and NEVER be user input
@@ -100,8 +110,8 @@ pub(crate) fn get_releases(
100110
}
101111
);
102112

103-
conn.query(query.as_str(), &[&limit, &offset, &filter_failed])
104-
.unwrap()
113+
Ok(conn
114+
.query(query.as_str(), &[&limit, &offset, &filter_failed])?
105115
.into_iter()
106116
.map(|row| Release {
107117
name: row.get(0),
@@ -112,7 +122,7 @@ pub(crate) fn get_releases(
112122
build_time: row.get(5),
113123
stars: row.get::<_, Option<i32>>(6).unwrap_or(0),
114124
})
115-
.collect()
125+
.collect())
116126
}
117127

118128
struct SearchResult {
@@ -255,9 +265,12 @@ impl_webpage! {
255265
HomePage = "core/home.html",
256266
}
257267

258-
pub fn home_page(req: &mut Request) -> IronResult<Response> {
268+
pub fn home_page(req: &mut Request) -> IronResult<IronResponse> {
259269
let mut conn = extension!(req, Pool).get()?;
260-
let recent_releases = get_releases(&mut conn, 1, RELEASES_IN_HOME, Order::ReleaseTime, true);
270+
let recent_releases = ctry!(
271+
req,
272+
get_releases(&mut conn, 1, RELEASES_IN_HOME, Order::ReleaseTime, true)
273+
);
261274

262275
HomePage { recent_releases }.into_response(req)
263276
}
@@ -272,9 +285,12 @@ impl_webpage! {
272285
content_type = ContentType(Mime(TopLevel::Application, SubLevel::Xml, vec![])),
273286
}
274287

275-
pub fn releases_feed_handler(req: &mut Request) -> IronResult<Response> {
288+
pub fn releases_feed_handler(req: &mut Request) -> IronResult<IronResponse> {
276289
let mut conn = extension!(req, Pool).get()?;
277-
let recent_releases = get_releases(&mut conn, 1, RELEASES_IN_FEED, Order::ReleaseTime, true);
290+
let recent_releases = ctry!(
291+
req,
292+
get_releases(&mut conn, 1, RELEASES_IN_FEED, Order::ReleaseTime, true)
293+
);
278294

279295
ReleaseFeed { recent_releases }.into_response(req)
280296
}
@@ -290,25 +306,26 @@ struct ViewReleases {
290306
owner: Option<String>,
291307
}
292308

293-
impl_webpage! {
309+
impl_axum_webpage! {
294310
ViewReleases = "releases/releases.html",
295311
}
296312

297313
#[derive(Debug, Copy, Clone, PartialEq, Eq, Serialize)]
298314
#[serde(rename_all = "kebab-case")]
299-
pub(super) enum ReleaseType {
315+
pub(crate) enum ReleaseType {
300316
Recent,
301317
Stars,
302318
RecentFailures,
303319
Failures,
304320
Search,
305321
}
306322

307-
fn releases_handler(req: &mut Request, release_type: ReleaseType) -> IronResult<Response> {
308-
let page_number: i64 = extension!(req, Router)
309-
.find("page")
310-
.and_then(|page_num| page_num.parse().ok())
311-
.unwrap_or(1);
323+
pub(crate) async fn releases_handler(
324+
pool: Pool,
325+
page: Option<i64>,
326+
release_type: ReleaseType,
327+
) -> WebResult<impl IntoResponse> {
328+
let page_number = page.unwrap_or(1);
312329

313330
let (description, release_order, latest_only) = match release_type {
314331
ReleaseType::Recent => ("Recently uploaded crates", Order::ReleaseTime, false),
@@ -329,52 +346,65 @@ fn releases_handler(req: &mut Request, release_type: ReleaseType) -> IronResult<
329346
}
330347
};
331348

332-
let releases = {
333-
let mut conn = extension!(req, Pool).get()?;
349+
let releases = spawn_blocking(move || -> Result<_> {
350+
let mut conn = pool.get()?;
334351
get_releases(
335352
&mut conn,
336353
page_number,
337354
RELEASES_IN_RELEASES,
338355
release_order,
339356
latest_only,
340357
)
341-
};
358+
})
359+
.await
360+
.context("failed to join thread")??;
342361

343362
// Show next and previous page buttons
344363
let (show_next_page, show_previous_page) = (
345364
releases.len() == RELEASES_IN_RELEASES as usize,
346365
page_number != 1,
347366
);
348367

349-
ViewReleases {
368+
Ok(ViewReleases {
350369
releases,
351370
description: description.into(),
352371
release_type,
353372
show_next_page,
354373
show_previous_page,
355374
page_number,
356375
owner: None,
357-
}
358-
.into_response(req)
376+
})
359377
}
360378

361-
pub fn recent_releases_handler(req: &mut Request) -> IronResult<Response> {
362-
releases_handler(req, ReleaseType::Recent)
379+
pub(crate) async fn recent_releases_handler(
380+
page: Option<Path<i64>>,
381+
Extension(pool): Extension<Pool>,
382+
) -> WebResult<impl IntoResponse> {
383+
releases_handler(pool, page.map(|p| p.0), ReleaseType::Recent).await
363384
}
364385

365-
pub fn releases_by_stars_handler(req: &mut Request) -> IronResult<Response> {
366-
releases_handler(req, ReleaseType::Stars)
386+
pub(crate) async fn releases_by_stars_handler(
387+
page: Option<Path<i64>>,
388+
Extension(pool): Extension<Pool>,
389+
) -> WebResult<impl IntoResponse> {
390+
releases_handler(pool, page.map(|p| p.0), ReleaseType::Stars).await
367391
}
368392

369-
pub fn releases_recent_failures_handler(req: &mut Request) -> IronResult<Response> {
370-
releases_handler(req, ReleaseType::RecentFailures)
393+
pub(crate) async fn releases_recent_failures_handler(
394+
page: Option<Path<i64>>,
395+
Extension(pool): Extension<Pool>,
396+
) -> WebResult<impl IntoResponse> {
397+
releases_handler(pool, page.map(|p| p.0), ReleaseType::RecentFailures).await
371398
}
372399

373-
pub fn releases_failures_by_stars_handler(req: &mut Request) -> IronResult<Response> {
374-
releases_handler(req, ReleaseType::Failures)
400+
pub(crate) async fn releases_failures_by_stars_handler(
401+
page: Option<Path<i64>>,
402+
Extension(pool): Extension<Pool>,
403+
) -> WebResult<impl IntoResponse> {
404+
releases_handler(pool, page.map(|p| p.0), ReleaseType::Failures).await
375405
}
376406

377-
pub fn owner_handler(req: &mut Request) -> IronResult<Response> {
407+
pub fn owner_handler(req: &mut Request) -> IronResult<IronResponse> {
378408
let router = extension!(req, Router);
379409
let mut owner = router.find("owner").unwrap();
380410
if owner.starts_with('@') {
@@ -414,7 +444,7 @@ impl Default for Search {
414444
}
415445
}
416446

417-
fn redirect_to_random_crate(req: &Request, conn: &mut PoolClient) -> IronResult<Response> {
447+
fn redirect_to_random_crate(req: &Request, conn: &mut PoolClient) -> IronResult<IronResponse> {
418448
// We try to find a random crate and redirect to it.
419449
//
420450
// The query is efficient, but relies on a static factor which depends
@@ -480,7 +510,7 @@ impl_webpage! {
480510
status = |search| search.status,
481511
}
482512

483-
pub fn search_handler(req: &mut Request) -> IronResult<Response> {
513+
pub fn search_handler(req: &mut Request) -> IronResult<IronResponse> {
484514
let url = req.url.as_ref();
485515
let mut params: HashMap<_, _> = url.query_pairs().collect();
486516
let query = params
@@ -526,7 +556,7 @@ pub fn search_handler(req: &mut Request) -> IronResult<Response> {
526556
ctry!(req, Url::parse(&format!("{base}/crate/{krate}/{version}")))
527557
};
528558

529-
let mut resp = Response::with((status::Found, Redirect(url)));
559+
let mut resp = IronResponse::with((status::Found, Redirect(url)));
530560
resp.headers.set(Expires(HttpDate(time::now())));
531561

532562
return Ok(resp);
@@ -607,7 +637,7 @@ impl_webpage! {
607637
ReleaseActivity = "releases/activity.html",
608638
}
609639

610-
pub fn activity_handler(req: &mut Request) -> IronResult<Response> {
640+
pub fn activity_handler(req: &mut Request) -> IronResult<IronResponse> {
611641
let mut conn = extension!(req, Pool).get()?;
612642

613643
let data: Vec<(NaiveDate, i64, i64)> = ctry!(
@@ -676,7 +706,7 @@ impl_webpage! {
676706
BuildQueuePage = "releases/build_queue.html",
677707
}
678708

679-
pub fn build_queue_handler(req: &mut Request) -> IronResult<Response> {
709+
pub fn build_queue_handler(req: &mut Request) -> IronResult<IronResponse> {
680710
let mut queue = ctry!(req, extension!(req, BuildQueue).queued_crates());
681711
for krate in queue.iter_mut() {
682712
// The priority here is inverted: in the database if a crate has a higher priority it
@@ -730,7 +760,7 @@ mod tests {
730760
// release without stars will not be shown
731761
env.fake_release().name("baz").version("1.0.0").create()?;
732762

733-
let releases = get_releases(&mut db.conn(), 1, 10, Order::GithubStars, true);
763+
let releases = get_releases(&mut db.conn(), 1, 10, Order::GithubStars, true).unwrap();
734764
assert_eq!(
735765
vec![
736766
"bar", // 20 stars

src/web/routes.rs

Lines changed: 32 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,38 @@ pub(super) fn build_axum_routes() -> AxumRouter {
6161
"/about/builds",
6262
get_internal(super::sitemap::about_builds_handler),
6363
)
64+
.route(
65+
"/releases",
66+
get_internal(super::releases::recent_releases_handler),
67+
)
68+
.route(
69+
"/releases/recent/:page",
70+
get_internal(super::releases::recent_releases_handler),
71+
)
72+
.route(
73+
"/releases/stars",
74+
get_internal(super::releases::releases_by_stars_handler),
75+
)
76+
.route(
77+
"/releases/stars/:page",
78+
get_internal(super::releases::releases_by_stars_handler),
79+
)
80+
.route(
81+
"/releases/recent-failures",
82+
get_internal(super::releases::releases_recent_failures_handler),
83+
)
84+
.route(
85+
"/releases/recent-failures/:page",
86+
get_internal(super::releases::releases_recent_failures_handler),
87+
)
88+
.route(
89+
"/releases/failures",
90+
get_internal(super::releases::releases_failures_by_stars_handler),
91+
)
92+
.route(
93+
"/releases/failures/:page",
94+
get_internal(super::releases::releases_failures_by_stars_handler),
95+
)
6496
}
6597

6698
// REFACTOR: Break this into smaller initialization functions
@@ -105,41 +137,12 @@ pub(super) fn build_routes() -> Routes {
105137
routes.internal_page("/about/metrics", super::metrics::metrics_handler);
106138
routes.internal_page("/about/:subpage", super::sitemap::about_handler);
107139

108-
routes.internal_page("/releases", super::releases::recent_releases_handler);
109140
routes.static_resource("/releases/feed", super::releases::releases_feed_handler);
110141
routes.internal_page("/releases/:owner", super::releases::owner_handler);
111142
routes.internal_page("/releases/:owner/:page", super::releases::owner_handler);
112143
routes.internal_page("/releases/activity", super::releases::activity_handler);
113144
routes.internal_page("/releases/search", super::releases::search_handler);
114145
routes.internal_page("/releases/queue", super::releases::build_queue_handler);
115-
routes.internal_page(
116-
"/releases/recent/:page",
117-
super::releases::recent_releases_handler,
118-
);
119-
routes.internal_page(
120-
"/releases/stars",
121-
super::releases::releases_by_stars_handler,
122-
);
123-
routes.internal_page(
124-
"/releases/stars/:page",
125-
super::releases::releases_by_stars_handler,
126-
);
127-
routes.internal_page(
128-
"/releases/recent-failures",
129-
super::releases::releases_recent_failures_handler,
130-
);
131-
routes.internal_page(
132-
"/releases/recent-failures/:page",
133-
super::releases::releases_recent_failures_handler,
134-
);
135-
routes.internal_page(
136-
"/releases/failures",
137-
super::releases::releases_failures_by_stars_handler,
138-
);
139-
routes.internal_page(
140-
"/releases/failures/:page",
141-
super::releases::releases_failures_by_stars_handler,
142-
);
143146

144147
routes.internal_page("/crate/:name", super::crate_details::crate_details_handler);
145148
routes.internal_page(

0 commit comments

Comments
 (0)