@@ -2,6 +2,7 @@ use askama::Template;
22use askama_web:: WebTemplate ;
33use axum:: http:: StatusCode ;
44use axum:: response:: { IntoResponse , Response } ;
5+ use snafu:: ErrorCompat ;
56use snafu:: prelude:: * ;
67
78use super :: free_space:: FreeSpaceError ;
@@ -15,30 +16,43 @@ pub enum AppStateError {
1516 API { source : hightorrent_api:: ApiError } ,
1617 #[ snafu( display( "Failed to get free space information" ) ) ]
1718 FreeSpace { source : FreeSpaceError } ,
19+ #[ snafu( display( "An other error occurred" ) ) ]
20+ Other {
21+ source : Box < dyn snafu:: Error + Send + Sync + ' static > ,
22+ } ,
23+ }
24+
25+ impl AppStateError {
26+ pub fn inner_errors ( & self ) -> Vec < Box < dyn std:: error:: Error + ' _ > > {
27+ let mut inner_errors = vec ! [ ] ;
28+ for error in self . iter_chain ( ) . skip ( 1 ) {
29+ inner_errors. push ( Box :: new ( error) . into ( ) ) ;
30+ }
31+ inner_errors
32+ }
1833}
1934
2035/// Global error page generated from an [AppStateError].
21- #[ derive( Clone , Debug , Template , WebTemplate ) ]
36+ #[ derive( Debug , Template , WebTemplate ) ]
2237#[ template( path = "error.html" ) ]
2338pub struct AppStateErrorContext {
2439 state : AppStateErrorContextInner ,
2540}
2641
2742/// Helper struct so we can reuse base.html
2843/// with all it's `state.foo` expressions.
29- #[ derive( Clone , Debug ) ]
44+ #[ derive( Debug ) ]
3045pub struct AppStateErrorContextInner {
31- // TODO: typed errors
32- // errors: Vec<AppStateError>,
33- errors : Vec < String > ,
46+ // TODO: askama doesn't handle recursion well, so we convert
47+ // all errors to strings. Maybe related to:
48+ // https://github.com/askama-rs/askama/issues/393
49+ errors : Vec < AppStateError > ,
3450}
3551
3652impl From < AppStateError > for AppStateErrorContext {
3753 fn from ( e : AppStateError ) -> Self {
3854 Self {
39- state : AppStateErrorContextInner {
40- errors : vec ! [ e. to_string( ) ] ,
41- } ,
55+ state : AppStateErrorContextInner { errors : vec ! [ e] } ,
4256 }
4357 }
4458}
@@ -49,3 +63,19 @@ impl IntoResponse for AppStateError {
4963 ( StatusCode :: INTERNAL_SERVER_ERROR , error_context) . into_response ( )
5064 }
5165}
66+
67+ #[ cfg( test) ]
68+ mod tests {
69+ use super :: * ;
70+
71+ #[ test]
72+ fn can_extract_from_any_error ( ) {
73+ let res: Result < _ , AppStateError > =
74+ std:: fs:: read ( "/tmp/qsjlkdjsqlkdsqfsqhsjklfhalkjfkjh.toml" )
75+ . boxed ( )
76+ . context ( OtherSnafu ) ;
77+
78+ assert ! ( res. is_err( ) ) ;
79+ assert_eq ! ( & res. unwrap_err( ) . to_string( ) , "An other error occurred" ) ;
80+ }
81+ }
0 commit comments