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