Skip to content

Commit 00ede2d

Browse files
committed
Add an optional request URL mapping function to WASM asset io
1 parent 8e24209 commit 00ede2d

File tree

1 file changed

+25
-4
lines changed

1 file changed

+25
-4
lines changed

crates/bevy_asset/src/io/wasm.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use crate::io::{
33
};
44
use alloc::{borrow::ToOwned, boxed::Box, format};
55
use js_sys::{Uint8Array, JSON};
6-
use std::path::{Path, PathBuf};
6+
use std::{
7+
borrow::Cow,
8+
path::{Path, PathBuf},
9+
};
710
use tracing::error;
811
use wasm_bindgen::{prelude::wasm_bindgen, JsCast, JsValue};
912
use wasm_bindgen_futures::JsFuture;
@@ -27,15 +30,27 @@ extern "C" {
2730
/// Reader implementation for loading assets via HTTP in Wasm.
2831
pub struct HttpWasmAssetReader {
2932
root_path: PathBuf,
33+
request_mapper: Option<Box<dyn Fn(&str) -> Cow<str> + Send + Sync + 'static>>,
3034
}
3135

3236
impl HttpWasmAssetReader {
3337
/// Creates a new `WasmAssetReader`. The path provided will be used to build URLs to query for assets.
3438
pub fn new<P: AsRef<Path>>(path: P) -> Self {
3539
Self {
3640
root_path: path.as_ref().to_owned(),
41+
request_mapper: None,
3742
}
3843
}
44+
45+
/// Sets a mapper function to modify the request URL for each asset fetch. This can be used to
46+
/// add query parameters or modify the path in any way.
47+
pub fn with_request_mapper<F>(mut self, mapper: F) -> Self
48+
where
49+
F: Fn(&str) -> Cow<str> + Send + Sync + 'static,
50+
{
51+
self.request_mapper = Some(Box::new(mapper));
52+
self
53+
}
3954
}
4055

4156
fn js_value_to_err(context: &str) -> impl FnOnce(JsValue) -> std::io::Error + '_ {
@@ -57,14 +72,20 @@ impl HttpWasmAssetReader {
5772
&self,
5873
path: PathBuf,
5974
) -> Result<impl Reader + use<>, AssetReaderError> {
75+
let path = path.to_str().unwrap();
76+
let fetch_path = self
77+
.request_mapper
78+
.as_ref()
79+
.map_or_else(|| Cow::Borrowed(path), |mapper| mapper(path));
80+
6081
// The JS global scope includes a self-reference via a specializing name, which can be used to determine the type of global context available.
6182
let global: Global = js_sys::global().unchecked_into();
6283
let promise = if !global.window().is_undefined() {
6384
let window: web_sys::Window = global.unchecked_into();
64-
window.fetch_with_str(path.to_str().unwrap())
85+
window.fetch_with_str(&fetch_path)
6586
} else if !global.worker().is_undefined() {
6687
let worker: web_sys::WorkerGlobalScope = global.unchecked_into();
67-
worker.fetch_with_str(path.to_str().unwrap())
88+
worker.fetch_with_str(&fetch_path)
6889
} else {
6990
let error = std::io::Error::other("Unsupported JavaScript global context");
7091
return Err(AssetReaderError::Io(error.into()));
@@ -85,7 +106,7 @@ impl HttpWasmAssetReader {
85106
// Some web servers, including itch.io's CDN, return 403 when a requested file isn't present.
86107
// TODO: remove handling of 403 as not found when it's easier to configure
87108
// see https://github.com/bevyengine/bevy/pull/19268#pullrequestreview-2882410105
88-
403 | 404 => Err(AssetReaderError::NotFound(path)),
109+
403 | 404 => Err(AssetReaderError::NotFound(path.into())),
89110
status => Err(AssetReaderError::HttpError(status)),
90111
}
91112
}

0 commit comments

Comments
 (0)