@@ -36,15 +36,80 @@ async fn main() -> color_eyre::Result<()> {
3636
3737 let api = warp:: path ( "api" )
3838 . and ( handlers:: routes ( db) )
39- . recover ( rejections:: handle_rejection)
4039 . with ( warp:: cors ( ) . allow_any_origin ( ) ) ;
40+ let homepage = warp:: get ( ) . and_then ( statics:: homepage) ;
41+ let statics = statics:: routes ( ) ;
42+
43+ let routes = api
44+ . or ( statics)
45+ . or ( homepage)
46+ . recover ( rejections:: handle_rejection) ;
4147
4248 let address = args. address . parse :: < std:: net:: SocketAddr > ( ) ?;
43- warp:: serve ( api ) . run ( address) . await ;
49+ warp:: serve ( routes ) . run ( address) . await ;
4450
4551 Ok ( ( ) )
4652}
4753
54+ mod statics {
55+ use std:: path:: Path ;
56+
57+ use include_dir:: { include_dir, Dir } ;
58+ use warp:: {
59+ http:: {
60+ header:: { CACHE_CONTROL , CONTENT_TYPE } ,
61+ Response ,
62+ } ,
63+ Filter ,
64+ } ;
65+
66+ static STATIC_DIR : Dir = include_dir ! ( "ui/dist" ) ;
67+
68+ async fn send_file ( path : warp:: path:: Tail ) -> Result < impl warp:: Reply , warp:: Rejection > {
69+ let path = Path :: new ( path. as_str ( ) ) ;
70+ let file = STATIC_DIR
71+ . get_file ( path)
72+ . ok_or_else ( warp:: reject:: not_found) ?;
73+
74+ let content_type = match file. path ( ) . extension ( ) {
75+ Some ( ext) if ext == "css" => "text/css" ,
76+ Some ( ext) if ext == "svg" => "image/svg+xml" ,
77+ Some ( ext) if ext == "js" => "text/javascript" ,
78+ Some ( ext) if ext == "html" => "text/html" ,
79+ _ => "application/octet-stream" ,
80+ } ;
81+
82+ let resp = Response :: builder ( )
83+ . header ( CONTENT_TYPE , content_type)
84+ . header ( CACHE_CONTROL , "max-age=3600, must-revalidate" )
85+ . body ( file. contents ( ) )
86+ . unwrap ( ) ;
87+
88+ Ok ( resp)
89+ }
90+
91+ pub async fn homepage ( ) -> Result < impl warp:: Reply , warp:: Rejection > {
92+ let file = STATIC_DIR
93+ . get_file ( "index.html" )
94+ . ok_or_else ( warp:: reject:: not_found) ?;
95+
96+ let resp = Response :: builder ( )
97+ . header ( CONTENT_TYPE , "text/html" )
98+ . header ( CACHE_CONTROL , "max-age=3600, must-revalidate" )
99+ . body ( file. contents ( ) )
100+ . unwrap ( ) ;
101+
102+ Ok ( resp)
103+ }
104+
105+ pub fn routes ( ) -> impl Filter < Extract = ( impl warp:: Reply , ) , Error = warp:: Rejection > + Clone {
106+ let index = warp:: path:: end ( ) . and_then ( homepage) ;
107+ let other = warp:: path:: tail ( ) . and_then ( send_file) ;
108+
109+ index. or ( other)
110+ }
111+ }
112+
48113#[ derive( Clone ) ]
49114struct TheDB {
50115 path : String ,
0 commit comments