Skip to content

Commit e092d41

Browse files
committed
make the inner responder async with timeout
1 parent 83bb099 commit e092d41

1 file changed

Lines changed: 106 additions & 46 deletions

File tree

crates/tauri/src/protocol/tauri.rs

Lines changed: 106 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@
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-
108
use http::{Request, Response as HttpResponse, StatusCode, header::CONTENT_TYPE};
9+
use std::{borrow::Cow, marker::PhantomData, sync::Arc, time::Duration};
1110
use tauri_utils::config::HeaderAddition;
1211

1312
use 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.
3435
pub 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

Comments
 (0)