Skip to content

Commit

Permalink
feat(wasm): support request timeout
Browse files Browse the repository at this point in the history
fixes #1135 #1274
  • Loading branch information
flisky committed Feb 24, 2023
1 parent bb8fec4 commit e063ad2
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 1 deletion.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ winreg = "0.10"
# wasm

[target.'cfg(target_arch = "wasm32")'.dependencies]
gloo-timers = "0.2.6"
js-sys = "0.3.45"
serde_json = "1.0"
wasm-bindgen = "0.2.68"
Expand Down
5 changes: 4 additions & 1 deletion src/wasm/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,10 @@ async fn fetch(req: Request) -> crate::Result<Response> {
}
}

let abort = AbortGuard::new()?;
let mut abort = AbortGuard::new()?;
if let Some(timeout) = req.timeout() {
abort.timeout(*timeout);
}
init.signal(Some(&abort.signal()));

let js_req = web_sys::Request::new_with_str_and_init(req.url().as_str(), &init)
Expand Down
15 changes: 15 additions & 0 deletions src/wasm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use std::convert::TryInto;
use std::time::Duration;

use gloo_timers::callback::Timeout;
use wasm_bindgen::JsCast;
use web_sys::{AbortController, AbortSignal};

Expand Down Expand Up @@ -30,6 +34,7 @@ where
/// A guard that cancels a fetch request when dropped.
struct AbortGuard {
ctrl: AbortController,
_timeout: Option<Timeout>,
}

impl AbortGuard {
Expand All @@ -38,12 +43,22 @@ impl AbortGuard {
ctrl: AbortController::new()
.map_err(crate::error::wasm)
.map_err(crate::error::builder)?,
_timeout: None,
})
}

fn signal(&self) -> AbortSignal {
self.ctrl.signal()
}

fn timeout(&mut self, timeout: Duration) {
let millis = timeout.as_millis().try_into().expect("timeout");
let ctrl = self.ctrl.clone();
let timeout = Timeout::new(millis, move || ctrl.abort());
if let Some(old) = self._timeout.replace(timeout) {
old.cancel();
}
}
}

impl Drop for AbortGuard {
Expand Down
25 changes: 25 additions & 0 deletions src/wasm/request.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::convert::TryFrom;
use std::fmt;
use std::time::Duration;

use bytes::Bytes;
use http::{request::Parts, Method, Request as HttpRequest};
Expand All @@ -18,6 +19,7 @@ pub struct Request {
url: Url,
headers: HeaderMap,
body: Option<Body>,
timeout: Option<Duration>,
pub(super) cors: bool,
pub(super) credentials: Option<RequestCredentials>,
}
Expand All @@ -37,6 +39,7 @@ impl Request {
url,
headers: HeaderMap::new(),
body: None,
timeout: None,
cors: true,
credentials: None,
}
Expand Down Expand Up @@ -90,6 +93,18 @@ impl Request {
&mut self.body
}

/// Get the timeout.
#[inline]
pub fn timeout(&self) -> Option<&Duration> {
self.timeout.as_ref()
}

/// Get a mutable reference to the timeout.
#[inline]
pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
&mut self.timeout
}

/// Attempts to clone the `Request`.
///
/// None is returned if a body is which can not be cloned.
Expand All @@ -104,6 +119,7 @@ impl Request {
url: self.url.clone(),
headers: self.headers.clone(),
body,
timeout: self.timeout.clone(),
cors: self.cors,
credentials: self.credentials,
})
Expand Down Expand Up @@ -233,6 +249,14 @@ impl RequestBuilder {
self
}

/// Enables a request timeout.
pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
if let Ok(ref mut req) = self.request {
*req.timeout_mut() = Some(timeout);
}
self
}

/// TODO
#[cfg(feature = "multipart")]
#[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
Expand Down Expand Up @@ -449,6 +473,7 @@ where
url,
headers,
body: Some(body.into()),
timeout: None,
cors: true,
credentials: None,
})
Expand Down

0 comments on commit e063ad2

Please sign in to comment.