@@ -9,19 +9,23 @@ use axum::extract::{Query, Request, State};
99use axum:: handler:: HandlerWithoutStateExt ;
1010use axum:: http:: Uri ;
1111use axum:: response:: IntoResponse ;
12- use axum:: routing:: get;
12+ use axum:: routing:: { get, post } ;
1313use axum:: Router ;
1414use clap:: Parser ;
15- use function_router:: { route_meta, Route , ServerApp , ServerAppProps } ;
15+ use function_router:: { route_meta, Route } ;
1616use futures:: stream:: { self , StreamExt } ;
1717use hyper:: body:: Incoming ;
1818use hyper_util:: rt:: TokioIo ;
1919use hyper_util:: server;
20+ use ssr_router:: {
21+ LinkedAuthor , LinkedPost , LinkedPostMeta , ServerApp , ServerAppProps , LINK_ENDPOINT ,
22+ } ;
2023use tokio:: net:: TcpListener ;
2124use tower:: Service ;
2225use tower_http:: cors:: CorsLayer ;
2326use tower_http:: services:: ServeDir ;
2427use yew:: platform:: Runtime ;
28+ use yew_link:: { linked_state_handler, Resolver , ResolverProp } ;
2529use yew_router:: prelude:: Routable ;
2630
2731// We use jemalloc as it produces better performance.
@@ -46,25 +50,36 @@ fn head_tags_for(path: &str) -> String {
4650 )
4751}
4852
53+ #[ derive( Clone ) ]
54+ struct AppState {
55+ index_html_before : String ,
56+ index_html_after : String ,
57+ resolver : ResolverProp ,
58+ }
59+
4960async fn render (
5061 url : Uri ,
5162 Query ( queries) : Query < HashMap < String , String > > ,
52- State ( ( index_html_before , index_html_after ) ) : State < ( String , String ) > ,
63+ State ( state ) : State < AppState > ,
5364) -> impl IntoResponse {
5465 let path = url. path ( ) . to_owned ( ) ;
5566
5667 // Inject route-specific <head> tags before </head>, outside of Yew rendering.
57- let before = index_html_before. replace ( "</head>" , & format ! ( "{}</head>" , head_tags_for( & path) ) ) ;
68+ let before = state
69+ . index_html_before
70+ . replace ( "</head>" , & format ! ( "{}</head>" , head_tags_for( & path) ) ) ;
71+ let resolver = state. resolver . clone ( ) ;
5872
5973 let renderer = yew:: ServerRenderer :: < ServerApp > :: with_props ( move || ServerAppProps {
6074 url : path. into ( ) ,
6175 queries,
76+ resolver,
6277 } ) ;
6378
6479 Body :: from_stream (
6580 stream:: once ( async move { before } )
6681 . chain ( renderer. render_stream ( ) )
67- . chain ( stream:: once ( async move { index_html_after } ) )
82+ . chain ( stream:: once ( async move { state . index_html_after } ) )
6883 . map ( Result :: < _ , Infallible > :: Ok ) ,
6984 )
7085}
@@ -94,35 +109,44 @@ where
94109#[ tokio:: main]
95110async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
96111 let exec = Executor :: default ( ) ;
97-
98112 env_logger:: init ( ) ;
99-
100113 let opts = Opt :: parse ( ) ;
101114
115+ let resolver_prop: ResolverProp = Resolver :: new ( )
116+ . register_linked :: < LinkedPost > ( ( ) )
117+ . register_linked :: < LinkedAuthor > ( ( ) )
118+ . register_linked :: < LinkedPostMeta > ( ( ) )
119+ . into ( ) ;
120+ let arc_resolver = resolver_prop. 0 . clone ( ) ;
121+
102122 let index_html_s = tokio:: fs:: read_to_string ( opts. dir . join ( "index.html" ) )
103123 . await
104124 . expect ( "failed to read index.html" ) ;
105125
106126 let ( index_html_before, index_html_after) = index_html_s. split_once ( "<body>" ) . unwrap ( ) ;
107127 let mut index_html_before = index_html_before. to_owned ( ) ;
108128 index_html_before. push_str ( "<body>" ) ;
109-
110129 let index_html_after = index_html_after. to_owned ( ) ;
111130
131+ let app_state = AppState {
132+ index_html_before,
133+ index_html_after,
134+ resolver : resolver_prop,
135+ } ;
136+
112137 let app = Router :: new ( )
138+ . route (
139+ LINK_ENDPOINT ,
140+ post ( linked_state_handler) . with_state ( arc_resolver) ,
141+ )
113142 . fallback_service (
114143 ServeDir :: new ( opts. dir )
115144 . append_index_html_on_directories ( false )
116- . fallback (
117- get ( render)
118- . with_state ( ( index_html_before. clone ( ) , index_html_after. clone ( ) ) )
119- . into_service ( ) ,
120- ) ,
145+ . fallback ( get ( render) . with_state ( app_state) . into_service ( ) ) ,
121146 )
122147 . layer ( CorsLayer :: permissive ( ) ) ;
123148
124149 let addr: SocketAddr = ( [ 0 , 0 , 0 , 0 ] , 8080 ) . into ( ) ;
125-
126150 println ! ( "You can view the website at: http://localhost:8080/" ) ;
127151
128152 let listener = TcpListener :: bind ( addr) . await ?;
0 commit comments