Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix fetching assets in Web Workers #12134

Merged
merged 4 commits into from
Mar 25, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions crates/bevy_asset/src/io/wasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,25 @@ use bevy_log::error;
use bevy_utils::BoxedFuture;
use js_sys::{Uint8Array, JSON};
use std::path::{Path, PathBuf};
use wasm_bindgen::{JsCast, JsValue};
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
use wasm_bindgen_futures::JsFuture;
use web_sys::Response;

/// Represents the global object in the JavaScript context
#[wasm_bindgen]
extern "C" {
/// The [Global](https://developer.mozilla.org/en-US/docs/Glossary/Global_object) object.
type Global;
allsey87 marked this conversation as resolved.
Show resolved Hide resolved

/// The [window](https://developer.mozilla.org/en-US/docs/Web/API/Window) global object.
#[wasm_bindgen(method, getter, js_name = Window)]
allsey87 marked this conversation as resolved.
Show resolved Hide resolved
fn window(this: &Global) -> JsValue;

/// The [WorkerGlobalScope](https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope) global object.
#[wasm_bindgen(method, getter, js_name = WorkerGlobalScope)]
allsey87 marked this conversation as resolved.
Show resolved Hide resolved
fn worker(this: &Global) -> JsValue;
}

/// Reader implementation for loading assets via HTTP in WASM.
pub struct HttpWasmAssetReader {
root_path: PathBuf,
Expand Down Expand Up @@ -38,8 +53,22 @@ fn js_value_to_err<'a>(context: &'a str) -> impl FnOnce(JsValue) -> std::io::Err

impl HttpWasmAssetReader {
async fn fetch_bytes<'a>(&self, path: PathBuf) -> Result<Box<Reader<'a>>, AssetReaderError> {
let window = web_sys::window().unwrap();
let resp_value = JsFuture::from(window.fetch_with_str(path.to_str().unwrap()))
// The JS global scope includes a self-reference via a specialising name, which can be used to determine the type of global context available.
let global: Global = js_sys::global().unchecked_into();
allsey87 marked this conversation as resolved.
Show resolved Hide resolved
let promise = if !global.window().is_undefined() {
let window: web_sys::Window = global.unchecked_into();
window.fetch_with_str(path.to_str().unwrap())
} else if !global.worker().is_undefined() {
let worker: web_sys::WorkerGlobalScope = global.unchecked_into();
worker.fetch_with_str(path.to_str().unwrap())
} else {
let error = std::io::Error::new(
std::io::ErrorKind::Other,
"Unsupported JavaScript global context",
);
return Err(AssetReaderError::Io(error.into()));
};
let resp_value = JsFuture::from(promise)
.await
.map_err(js_value_to_err("fetch path"))?;
let resp = resp_value
Expand Down