From 801e2bae366ed6edb60ae49255fcf1709b42f3b5 Mon Sep 17 00:00:00 2001 From: Guillaume Depardon Date: Tue, 17 Mar 2020 15:39:48 +0100 Subject: [PATCH] Made requests work from within a web worker context This looks pretty hacky until something is done regarding https://github.com/rustwasm/wasm-bindgen/issues/1046 --- Cargo.toml | 1 + src/wasm/client.rs | 48 ++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 43d91698d..64dd34bf0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -141,6 +141,7 @@ features = [ "RequestMode", "Response", "Window", + "WorkerGlobalScope", ] [[example]] diff --git a/src/wasm/client.rs b/src/wasm/client.rs index 998370dd1..476d92036 100644 --- a/src/wasm/client.rs +++ b/src/wasm/client.rs @@ -101,6 +101,43 @@ impl Client { } } +use wasm_bindgen::{prelude::*, JsCast}; + +thread_local! { + static GLOBAL_WEB_CONTEXT: WebContext = WebContext::new(); +} + +#[derive(Debug)] +enum WebContext { + Window(web_sys::Window), + Worker(web_sys::WorkerGlobalScope), +} + +impl WebContext { + fn new() -> Self { + #[wasm_bindgen] + extern "C" { + type Global; + + #[wasm_bindgen(method, getter, js_name = Window)] + fn window(this: &Global) -> JsValue; + + #[wasm_bindgen(method, getter, js_name = WorkerGlobalScope)] + fn worker(this: &Global) -> JsValue; + } + + let global: Global = js_sys::global().unchecked_into(); + + if !global.window().is_undefined() { + Self::Window(global.unchecked_into()) + } else if !global.worker().is_undefined() { + Self::Worker(global.unchecked_into()) + } else { + panic!("Only supported in a browser or web worker"); + } + } +} + async fn fetch(req: Request) -> crate::Result { // Build the js Request let mut init = web_sys::RequestInit::new(); @@ -136,10 +173,13 @@ async fn fetch(req: Request) -> crate::Result { .map_err(crate::error::wasm) .map_err(crate::error::builder)?; - // Await the fetch() promise - let p = web_sys::window() - .expect("window should exist") - .fetch_with_request(&js_req); + let p = GLOBAL_WEB_CONTEXT.with(|g| { + match g { + WebContext::Window(w) => w.fetch_with_request(&js_req), + WebContext::Worker(w) => w.fetch_with_request(&js_req), + } + }); + let js_resp = super::promise::(p) .await .map_err(crate::error::request)?;