55//! Handler for the `tauri://` custom protocol, serving bundled app assets
66//! in production and proxying to the dev server on mobile during development.
77
8- use std:: borrow:: Cow ;
9-
108use http:: { Request , Response as HttpResponse , StatusCode , header:: CONTENT_TYPE } ;
9+ use std:: { borrow:: Cow , marker:: PhantomData , sync:: Arc , time:: Duration } ;
1110use tauri_utils:: config:: HeaderAddition ;
1211
1312use crate :: {
@@ -17,7 +16,9 @@ use crate::{
1716} ;
1817
1918#[ cfg( all( dev, mobile) ) ]
20- use std:: { collections:: HashMap , sync:: Mutex } ;
19+ use std:: collections:: HashMap ;
20+ #[ cfg( all( dev, mobile) ) ]
21+ use tokio:: sync:: Mutex ;
2122
2223#[ cfg( all( dev, mobile) ) ]
2324#[ derive( Clone ) ]
@@ -32,59 +33,119 @@ struct CachedResponse {
3233/// This handler serves your app's bundled assets (HTML, JS, CSS, etc.) in production,
3334/// and proxies requests to the dev server on mobile during development.
3435pub fn get < M : Manager < R > + Send + Sync + ' static , R : Runtime > (
35- # [ allow ( unused_variables ) ] manager : M ,
36+ manager : M ,
3637 window_origin : & str ,
3738 web_resource_request_handler : Option < Box < WebResourceRequestHandler > > ,
3839) -> UriSchemeProtocolHandler {
40+ let responder = RequestCallbackBuilder :: new ( manager, window_origin, web_resource_request_handler) ;
41+ Arc :: new ( responder) . into_callback ( )
42+ }
43+
44+ struct RequestCallbackBuilder < M , R > {
45+ manager : M ,
46+ window_origin : String ,
47+ web_resource_request_handler : Option < Box < WebResourceRequestHandler > > ,
3948 #[ cfg( all( dev, mobile) ) ]
40- let url = {
41- let mut url = manager
42- . manager ( )
43- . get_app_url ( window_origin. starts_with ( "https" ) )
44- . as_str ( )
45- . to_string ( ) ;
46- if url. ends_with ( '/' ) {
47- url. pop ( ) ;
48- }
49- url
50- } ;
49+ url : String ,
50+ #[ cfg( all( dev, mobile) ) ]
51+ response_cache : Mutex < HashMap < String , CachedResponse > > ,
52+ runtime : PhantomData < fn ( ) -> R > ,
53+ }
5154
52- let window_origin = window_origin. to_string ( ) ;
55+ impl < M , R > RequestCallbackBuilder < M , R >
56+ where
57+ M : Manager < R > + Send + Sync + ' static ,
58+ R : Runtime ,
59+ {
60+ fn new (
61+ manager : M ,
62+ window_origin : & str ,
63+ web_resource_request_handler : Option < Box < WebResourceRequestHandler > > ,
64+ ) -> Self {
65+ #[ cfg( all( dev, mobile) ) ]
66+ let response_cache = Mutex :: new ( HashMap :: new ( ) ) ;
5367
54- #[ cfg( all( dev, mobile) ) ]
55- let response_cache = std:: sync:: Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ;
56-
57- Box :: new ( move |_, request, responder| {
58- match get_response (
59- request,
60- & manager,
61- & window_origin,
62- web_resource_request_handler. as_deref ( ) ,
68+ #[ cfg( all( dev, mobile) ) ]
69+ let url = {
70+ let mut url = manager
71+ . manager ( )
72+ . get_app_url ( window_origin. starts_with ( "https" ) )
73+ . as_str ( )
74+ . to_string ( ) ;
75+ if url. ends_with ( '/' ) {
76+ url. pop ( ) ;
77+ }
78+ url. into ( )
79+ } ;
80+
81+ Self {
82+ manager,
83+ window_origin : window_origin. into ( ) ,
84+ web_resource_request_handler,
85+ #[ cfg( all( dev, mobile) ) ]
86+ url,
6387 #[ cfg( all( dev, mobile) ) ]
64- ( & url, & response_cache) ,
65- ) {
66- Ok ( response) => responder. respond ( response) ,
67- Err ( e) => responder. respond (
68- HttpResponse :: builder ( )
69- . status ( StatusCode :: INTERNAL_SERVER_ERROR )
70- . header ( CONTENT_TYPE , mime:: TEXT_PLAIN . essence_str ( ) )
71- . header ( "Access-Control-Allow-Origin" , & window_origin)
72- . body ( e. to_string ( ) . into_bytes ( ) )
73- . unwrap ( ) ,
74- ) ,
88+ response_cache,
89+ runtime : PhantomData ,
7590 }
76- } )
91+ }
92+
93+ fn into_callback ( self : Arc < Self > ) -> UriSchemeProtocolHandler {
94+ Box :: new ( move |_, request, responder| {
95+ let this = self . clone ( ) ;
96+ crate :: async_runtime:: spawn ( async move {
97+ let RequestCallbackBuilder {
98+ manager,
99+ window_origin,
100+ web_resource_request_handler,
101+ #[ cfg( all( dev, mobile) ) ]
102+ url,
103+ #[ cfg( all( dev, mobile) ) ]
104+ response_cache,
105+ ..
106+ } = & * this;
107+
108+ let resp_fut = get_response (
109+ request,
110+ manager,
111+ window_origin. as_str ( ) ,
112+ web_resource_request_handler. as_deref ( ) ,
113+ #[ cfg( all( dev, mobile) ) ]
114+ ( url. as_str ( ) , response_cache) ,
115+ ) ;
116+
117+ let timeout_fut = tokio:: time:: timeout ( Duration :: from_secs ( 10 ) , resp_fut) ;
118+
119+ match timeout_fut. await {
120+ Ok ( Ok ( response) ) => responder. respond ( response) ,
121+ Ok ( Err ( e) ) => responder. respond (
122+ HttpResponse :: builder ( )
123+ . status ( StatusCode :: INTERNAL_SERVER_ERROR )
124+ . header ( CONTENT_TYPE , mime:: TEXT_PLAIN . essence_str ( ) )
125+ . header ( "Access-Control-Allow-Origin" , window_origin. as_str ( ) )
126+ . body ( e. to_string ( ) . into_bytes ( ) )
127+ . unwrap ( ) ,
128+ ) ,
129+ Err ( e) => responder. respond (
130+ HttpResponse :: builder ( )
131+ . status ( StatusCode :: INTERNAL_SERVER_ERROR )
132+ . header ( CONTENT_TYPE , mime:: TEXT_PLAIN . essence_str ( ) )
133+ . header ( "Access-Control-Allow-Origin" , window_origin. as_str ( ) )
134+ . body ( e. to_string ( ) . into_bytes ( ) )
135+ . unwrap ( ) ,
136+ ) ,
137+ }
138+ } ) ;
139+ } )
140+ }
77141}
78142
79- fn get_response < M : Manager < R > + Send + Sync + ' static , R : Runtime > (
143+ async fn get_response < M : Manager < R > + Send + Sync + ' static , R : Runtime > (
80144 #[ allow( unused_mut) ] mut request : Request < Vec < u8 > > ,
81145 #[ allow( unused_variables) ] manager : & M ,
82146 window_origin : & str ,
83147 web_resource_request_handler : Option < & WebResourceRequestHandler > ,
84- #[ cfg( all( dev, mobile) ) ] ( url, response_cache) : (
85- & str ,
86- & std:: sync:: Arc < Mutex < HashMap < String , CachedResponse > > > ,
87- ) ,
148+ #[ cfg( all( dev, mobile) ) ] ( url, response_cache) : ( & str , & Mutex < HashMap < String , CachedResponse > > ) ,
88149) -> Result < HttpResponse < Cow < ' static , [ u8 ] > > , Box < dyn std:: error:: Error > > {
89150 // use the entire URI as we are going to proxy the request
90151 let path = if PROXY_DEV_SERVER {
@@ -170,9 +231,9 @@ fn get_response<M: Manager<R> + Send + Sync + 'static, R: Runtime>(
170231 proxy_builder = proxy_builder. header ( name, value) ;
171232 }
172233 proxy_builder = proxy_builder. body ( request. body ( ) . clone ( ) ) ;
173- match crate :: async_runtime :: safe_block_on ( proxy_builder. send ( ) ) {
234+ match proxy_builder. send ( ) . await {
174235 Ok ( r) => {
175- let mut response_cache_ = response_cache. lock ( ) . unwrap ( ) ;
236+ let mut response_cache_ = response_cache. lock ( ) . await ;
176237 let mut response = None ;
177238 if r. status ( ) == http:: StatusCode :: NOT_MODIFIED {
178239 response = response_cache_. get ( & url) ;
@@ -182,7 +243,7 @@ fn get_response<M: Manager<R> + Send + Sync + 'static, R: Runtime>(
182243 } else {
183244 let status = r. status ( ) ;
184245 let headers = r. headers ( ) . clone ( ) ;
185- let body = crate :: async_runtime :: safe_block_on ( r. bytes ( ) ) ?;
246+ let body = r. bytes ( ) . await ?;
186247 let response = CachedResponse {
187248 status,
188249 headers,
@@ -211,7 +272,6 @@ fn get_response<M: Manager<R> + Send + Sync + 'static, R: Runtime>(
211272 "" . to_string( )
212273 }
213274 ) ;
214- log:: error!( "{error_message}" ) ;
215275 return Err ( error_message. into ( ) ) ;
216276 }
217277 }
0 commit comments