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