@@ -9,19 +9,21 @@ 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:: { LinkedAuthor , LinkedPost , LinkedPostMeta , ServerApp , ServerAppProps } ;
2021use tokio:: net:: TcpListener ;
2122use tower:: Service ;
2223use tower_http:: cors:: CorsLayer ;
2324use tower_http:: services:: ServeDir ;
2425use yew:: platform:: Runtime ;
26+ use yew_link:: { linked_state_handler, Resolver , ResolverProp } ;
2527use yew_router:: prelude:: Routable ;
2628
2729// We use jemalloc as it produces better performance.
@@ -46,25 +48,36 @@ fn head_tags_for(path: &str) -> String {
4648 )
4749}
4850
51+ #[ derive( Clone ) ]
52+ struct AppState {
53+ index_html_before : String ,
54+ index_html_after : String ,
55+ resolver : ResolverProp ,
56+ }
57+
4958async fn render (
5059 url : Uri ,
5160 Query ( queries) : Query < HashMap < String , String > > ,
52- State ( ( index_html_before , index_html_after ) ) : State < ( String , String ) > ,
61+ State ( state ) : State < AppState > ,
5362) -> impl IntoResponse {
5463 let path = url. path ( ) . to_owned ( ) ;
5564
5665 // 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) ) ) ;
66+ let before = state
67+ . index_html_before
68+ . replace ( "</head>" , & format ! ( "{}</head>" , head_tags_for( & path) ) ) ;
69+ let resolver = state. resolver . clone ( ) ;
5870
5971 let renderer = yew:: ServerRenderer :: < ServerApp > :: with_props ( move || ServerAppProps {
6072 url : path. into ( ) ,
6173 queries,
74+ resolver,
6275 } ) ;
6376
6477 Body :: from_stream (
6578 stream:: once ( async move { before } )
6679 . chain ( renderer. render_stream ( ) )
67- . chain ( stream:: once ( async move { index_html_after } ) )
80+ . chain ( stream:: once ( async move { state . index_html_after } ) )
6881 . map ( Result :: < _ , Infallible > :: Ok ) ,
6982 )
7083}
@@ -94,35 +107,44 @@ where
94107#[ tokio:: main]
95108async fn main ( ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
96109 let exec = Executor :: default ( ) ;
97-
98110 env_logger:: init ( ) ;
99-
100111 let opts = Opt :: parse ( ) ;
101112
113+ let resolver_prop: ResolverProp = Resolver :: new ( )
114+ . register_linked :: < LinkedPost > ( ( ) )
115+ . register_linked :: < LinkedAuthor > ( ( ) )
116+ . register_linked :: < LinkedPostMeta > ( ( ) )
117+ . into ( ) ;
118+ let arc_resolver = resolver_prop. 0 . clone ( ) ;
119+
102120 let index_html_s = tokio:: fs:: read_to_string ( opts. dir . join ( "index.html" ) )
103121 . await
104122 . expect ( "failed to read index.html" ) ;
105123
106124 let ( index_html_before, index_html_after) = index_html_s. split_once ( "<body>" ) . unwrap ( ) ;
107125 let mut index_html_before = index_html_before. to_owned ( ) ;
108126 index_html_before. push_str ( "<body>" ) ;
109-
110127 let index_html_after = index_html_after. to_owned ( ) ;
111128
129+ let app_state = AppState {
130+ index_html_before,
131+ index_html_after,
132+ resolver : resolver_prop,
133+ } ;
134+
112135 let app = Router :: new ( )
136+ . route (
137+ "/api/link" ,
138+ post ( linked_state_handler) . with_state ( arc_resolver) ,
139+ )
113140 . fallback_service (
114141 ServeDir :: new ( opts. dir )
115142 . 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- ) ,
143+ . fallback ( get ( render) . with_state ( app_state) . into_service ( ) ) ,
121144 )
122145 . layer ( CorsLayer :: permissive ( ) ) ;
123146
124147 let addr: SocketAddr = ( [ 0 , 0 , 0 , 0 ] , 8080 ) . into ( ) ;
125-
126148 println ! ( "You can view the website at: http://localhost:8080/" ) ;
127149
128150 let listener = TcpListener :: bind ( addr) . await ?;
0 commit comments