@@ -4,24 +4,34 @@ use crate::{
4
4
build_queue:: QueuedCrate ,
5
5
cdn:: { self , CrateInvalidation } ,
6
6
db:: { Pool , PoolClient } ,
7
- impl_webpage,
7
+ impl_axum_webpage , impl_webpage,
8
8
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
+ } ,
10
15
BuildQueue , Config ,
11
16
} ;
12
- use anyhow:: { anyhow, Result } ;
17
+ use anyhow:: { anyhow, Context as _, Result } ;
18
+ use axum:: {
19
+ extract:: { Extension , Path } ,
20
+ response:: IntoResponse ,
21
+ } ;
13
22
use chrono:: { DateTime , NaiveDate , Utc } ;
14
23
use iron:: {
15
24
headers:: { ContentType , Expires , HttpDate } ,
16
25
mime:: { Mime , SubLevel , TopLevel } ,
17
26
modifiers:: Redirect ,
18
- status, IronError , IronResult , Request , Response , Url ,
27
+ status, IronError , IronResult , Request , Response as IronResponse , Url ,
19
28
} ;
20
29
use postgres:: Client ;
21
30
use router:: Router ;
22
31
use serde:: { Deserialize , Serialize } ;
23
32
use std:: collections:: { BTreeMap , HashMap } ;
24
33
use std:: str;
34
+ use tokio:: task:: spawn_blocking;
25
35
use tracing:: { debug, warn} ;
26
36
use url:: form_urlencoded;
27
37
@@ -63,7 +73,7 @@ pub(crate) fn get_releases(
63
73
limit : i64 ,
64
74
order : Order ,
65
75
latest_only : bool ,
66
- ) -> Vec < Release > {
76
+ ) -> Result < Vec < Release > > {
67
77
let offset = ( page - 1 ) * limit;
68
78
69
79
// WARNING: it is _crucial_ that this always be hard-coded and NEVER be user input
@@ -100,8 +110,8 @@ pub(crate) fn get_releases(
100
110
}
101
111
) ;
102
112
103
- conn . query ( query . as_str ( ) , & [ & limit , & offset , & filter_failed ] )
104
- . unwrap ( )
113
+ Ok ( conn
114
+ . query ( query . as_str ( ) , & [ & limit , & offset , & filter_failed ] ) ?
105
115
. into_iter ( )
106
116
. map ( |row| Release {
107
117
name : row. get ( 0 ) ,
@@ -112,7 +122,7 @@ pub(crate) fn get_releases(
112
122
build_time : row. get ( 5 ) ,
113
123
stars : row. get :: < _ , Option < i32 > > ( 6 ) . unwrap_or ( 0 ) ,
114
124
} )
115
- . collect ( )
125
+ . collect ( ) )
116
126
}
117
127
118
128
struct SearchResult {
@@ -255,9 +265,12 @@ impl_webpage! {
255
265
HomePage = "core/home.html" ,
256
266
}
257
267
258
- pub fn home_page ( req : & mut Request ) -> IronResult < Response > {
268
+ pub fn home_page ( req : & mut Request ) -> IronResult < IronResponse > {
259
269
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
+ ) ;
261
274
262
275
HomePage { recent_releases } . into_response ( req)
263
276
}
@@ -272,9 +285,12 @@ impl_webpage! {
272
285
content_type = ContentType ( Mime ( TopLevel :: Application , SubLevel :: Xml , vec![ ] ) ) ,
273
286
}
274
287
275
- pub fn releases_feed_handler ( req : & mut Request ) -> IronResult < Response > {
288
+ pub fn releases_feed_handler ( req : & mut Request ) -> IronResult < IronResponse > {
276
289
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
+ ) ;
278
294
279
295
ReleaseFeed { recent_releases } . into_response ( req)
280
296
}
@@ -290,25 +306,26 @@ struct ViewReleases {
290
306
owner : Option < String > ,
291
307
}
292
308
293
- impl_webpage ! {
309
+ impl_axum_webpage ! {
294
310
ViewReleases = "releases/releases.html" ,
295
311
}
296
312
297
313
#[ derive( Debug , Copy , Clone , PartialEq , Eq , Serialize ) ]
298
314
#[ serde( rename_all = "kebab-case" ) ]
299
- pub ( super ) enum ReleaseType {
315
+ pub ( crate ) enum ReleaseType {
300
316
Recent ,
301
317
Stars ,
302
318
RecentFailures ,
303
319
Failures ,
304
320
Search ,
305
321
}
306
322
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 ) ;
312
329
313
330
let ( description, release_order, latest_only) = match release_type {
314
331
ReleaseType :: Recent => ( "Recently uploaded crates" , Order :: ReleaseTime , false ) ,
@@ -329,52 +346,65 @@ fn releases_handler(req: &mut Request, release_type: ReleaseType) -> IronResult<
329
346
}
330
347
} ;
331
348
332
- let releases = {
333
- let mut conn = extension ! ( req , Pool ) . get ( ) ?;
349
+ let releases = spawn_blocking ( move || -> Result < _ > {
350
+ let mut conn = pool . get ( ) ?;
334
351
get_releases (
335
352
& mut conn,
336
353
page_number,
337
354
RELEASES_IN_RELEASES ,
338
355
release_order,
339
356
latest_only,
340
357
)
341
- } ;
358
+ } )
359
+ . await
360
+ . context ( "failed to join thread" ) ??;
342
361
343
362
// Show next and previous page buttons
344
363
let ( show_next_page, show_previous_page) = (
345
364
releases. len ( ) == RELEASES_IN_RELEASES as usize ,
346
365
page_number != 1 ,
347
366
) ;
348
367
349
- ViewReleases {
368
+ Ok ( ViewReleases {
350
369
releases,
351
370
description : description. into ( ) ,
352
371
release_type,
353
372
show_next_page,
354
373
show_previous_page,
355
374
page_number,
356
375
owner : None ,
357
- }
358
- . into_response ( req)
376
+ } )
359
377
}
360
378
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
363
384
}
364
385
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
367
391
}
368
392
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
371
398
}
372
399
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
375
405
}
376
406
377
- pub fn owner_handler ( req : & mut Request ) -> IronResult < Response > {
407
+ pub fn owner_handler ( req : & mut Request ) -> IronResult < IronResponse > {
378
408
let router = extension ! ( req, Router ) ;
379
409
let mut owner = router. find ( "owner" ) . unwrap ( ) ;
380
410
if owner. starts_with ( '@' ) {
@@ -414,7 +444,7 @@ impl Default for Search {
414
444
}
415
445
}
416
446
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 > {
418
448
// We try to find a random crate and redirect to it.
419
449
//
420
450
// The query is efficient, but relies on a static factor which depends
@@ -480,7 +510,7 @@ impl_webpage! {
480
510
status = |search| search. status,
481
511
}
482
512
483
- pub fn search_handler ( req : & mut Request ) -> IronResult < Response > {
513
+ pub fn search_handler ( req : & mut Request ) -> IronResult < IronResponse > {
484
514
let url = req. url . as_ref ( ) ;
485
515
let mut params: HashMap < _ , _ > = url. query_pairs ( ) . collect ( ) ;
486
516
let query = params
@@ -526,7 +556,7 @@ pub fn search_handler(req: &mut Request) -> IronResult<Response> {
526
556
ctry ! ( req, Url :: parse( & format!( "{base}/crate/{krate}/{version}" ) ) )
527
557
} ;
528
558
529
- let mut resp = Response :: with ( ( status:: Found , Redirect ( url) ) ) ;
559
+ let mut resp = IronResponse :: with ( ( status:: Found , Redirect ( url) ) ) ;
530
560
resp. headers . set ( Expires ( HttpDate ( time:: now ( ) ) ) ) ;
531
561
532
562
return Ok ( resp) ;
@@ -607,7 +637,7 @@ impl_webpage! {
607
637
ReleaseActivity = "releases/activity.html" ,
608
638
}
609
639
610
- pub fn activity_handler ( req : & mut Request ) -> IronResult < Response > {
640
+ pub fn activity_handler ( req : & mut Request ) -> IronResult < IronResponse > {
611
641
let mut conn = extension ! ( req, Pool ) . get ( ) ?;
612
642
613
643
let data: Vec < ( NaiveDate , i64 , i64 ) > = ctry ! (
@@ -676,7 +706,7 @@ impl_webpage! {
676
706
BuildQueuePage = "releases/build_queue.html" ,
677
707
}
678
708
679
- pub fn build_queue_handler ( req : & mut Request ) -> IronResult < Response > {
709
+ pub fn build_queue_handler ( req : & mut Request ) -> IronResult < IronResponse > {
680
710
let mut queue = ctry ! ( req, extension!( req, BuildQueue ) . queued_crates( ) ) ;
681
711
for krate in queue. iter_mut ( ) {
682
712
// The priority here is inverted: in the database if a crate has a higher priority it
@@ -730,7 +760,7 @@ mod tests {
730
760
// release without stars will not be shown
731
761
env. fake_release ( ) . name ( "baz" ) . version ( "1.0.0" ) . create ( ) ?;
732
762
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 ( ) ;
734
764
assert_eq ! (
735
765
vec![
736
766
"bar" , // 20 stars
0 commit comments