1
1
use std:: { net:: SocketAddr , sync:: Arc } ;
2
2
3
- use axum:: { routing:: get, Extension , Router , Server } ;
4
- use log:: info;
3
+ use axum:: {
4
+ http:: StatusCode ,
5
+ response:: IntoResponse ,
6
+ routing:: { get, post} ,
7
+ Extension , Router , Server ,
8
+ } ;
9
+ use tracing:: { error, info} ;
5
10
6
11
use tera:: Tera ;
7
12
8
- use crate :: routes:: { get_index, get_preview_ad, get_preview_video} ;
13
+ use crate :: routes:: { get_index, get_preview_ad, get_preview_video, post_slot_preview } ;
9
14
10
15
#[ derive( Debug ) ]
11
16
pub struct State {
@@ -17,6 +22,66 @@ pub struct Application {
17
22
state : Arc < State > ,
18
23
}
19
24
25
+ pub struct Error {
26
+ error : Box < dyn std:: error:: Error > ,
27
+ status : StatusCode ,
28
+ }
29
+
30
+ impl Error {
31
+ pub fn new < E > ( error : E , status : StatusCode ) -> Self
32
+ where
33
+ E : Into < Box < dyn std:: error:: Error > > ,
34
+ {
35
+ Self {
36
+ error : error. into ( ) ,
37
+ status,
38
+ }
39
+ }
40
+
41
+ /// Create a new [`Error`] from [`anyhow::Error`] with a custom [`StatusCode`]
42
+ /// instead of the default [`StatusCode::INTERNAL_SERVER_ERROR`].
43
+ pub fn anyhow_status ( error : anyhow:: Error , status : StatusCode ) -> Self {
44
+ Self {
45
+ error : error. into ( ) ,
46
+ status,
47
+ }
48
+ }
49
+ }
50
+
51
+ impl IntoResponse for Error {
52
+ fn into_response ( self ) -> axum:: response:: Response {
53
+ let response_tuple = match self . status {
54
+ StatusCode :: INTERNAL_SERVER_ERROR => {
55
+ error ! ( { error = %self . error} , "Server error" ) ;
56
+ ( StatusCode :: INTERNAL_SERVER_ERROR , self . error . to_string ( ) )
57
+ }
58
+ // we want to log any error that is with status > 500
59
+ status_code if status_code. as_u16 ( ) > 500 => {
60
+ error ! ( { error = %self . error} , "Server error" ) ;
61
+ ( status_code, self . error . to_string ( ) )
62
+ }
63
+ // anything else is < 500, so it's safe to not log it due to e.g. bad user input
64
+ status_code => ( status_code, self . error . to_string ( ) ) ,
65
+ } ;
66
+
67
+ response_tuple. into_response ( )
68
+ }
69
+ }
70
+
71
+ impl < E > From < E > for Error
72
+ where
73
+ E : Into < anyhow:: Error > ,
74
+ {
75
+ fn from ( err : E ) -> Self {
76
+ let anyhow_err: anyhow:: Error = err. into ( ) ;
77
+
78
+ Self {
79
+ error : anyhow_err. into ( ) ,
80
+ status : StatusCode :: INTERNAL_SERVER_ERROR ,
81
+ }
82
+ }
83
+ }
84
+
20
85
impl Application {
21
86
pub fn new ( ) -> Result < Self , Box < dyn std:: error:: Error > > {
22
87
let serve_dir = match std:: env:: current_dir ( ) . unwrap ( ) {
@@ -42,11 +107,15 @@ impl Application {
42
107
}
43
108
44
109
pub async fn run ( & self ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
110
+ let preview_routes = Router :: new ( )
111
+ . route ( "/" , post ( post_slot_preview) )
112
+ . route ( "/ad" , get ( get_preview_ad) )
113
+ . route ( "/video" , get ( get_preview_video) ) ;
114
+
45
115
// build our application with a single route
46
116
let app = Router :: new ( )
47
117
. route ( "/" , get ( get_index) )
48
- . route ( "/preview/ad" , get ( get_preview_ad) )
49
- . route ( "/preview/video" , get ( get_preview_video) )
118
+ . nest ( "/preview" , preview_routes)
50
119
. layer ( Extension ( self . state . clone ( ) ) ) ;
51
120
52
121
let socket_addr: SocketAddr = ( [ 127 , 0 , 0 , 1 ] , 3030 ) . into ( ) ;
0 commit comments