Skip to content

Commit 2b1f420

Browse files
authored
[wasm] Rework fetch (#61639)
* Unify some code and load mono-config.json using our _fetch_asset
1 parent 9a9a4f3 commit 2b1f420

File tree

2 files changed

+45
-59
lines changed

2 files changed

+45
-59
lines changed

src/mono/wasm/runtime/startup.ts

Lines changed: 43 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
import { INTERNAL, Module, MONO, runtimeHelpers } from "./modules";
5-
import { AllAssetEntryTypes, AssetEntry, CharPtr, CharPtrNull, EmscriptenModuleMono, GlobalizationMode, MonoConfig, TypedArray, VoidPtr, wasm_type_symbol } from "./types";
5+
import { AllAssetEntryTypes, AssetEntry, CharPtr, CharPtrNull, EmscriptenModuleMono, GlobalizationMode, MonoConfig, VoidPtr, wasm_type_symbol } from "./types";
66
import cwraps from "./cwraps";
77
import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug";
88
import { mono_wasm_globalization_init, mono_wasm_load_icu_data } from "./icu";
@@ -56,6 +56,43 @@ export function mono_wasm_set_runtime_options(options: string[]): void {
5656
cwraps.mono_wasm_parse_runtime_options(options.length, argv);
5757
}
5858

59+
async function _fetch_asset(url: string): Promise<Response> {
60+
try {
61+
if (typeof (fetch) === "function") {
62+
return fetch(url, { credentials: "same-origin" });
63+
}
64+
else if (ENVIRONMENT_IS_NODE) {
65+
// eslint-disable-next-line @typescript-eslint/no-var-requires
66+
const fs = require("fs");
67+
const arrayBuffer = await fs.promises.readFile(url);
68+
return <Response><any> {
69+
ok: true,
70+
url,
71+
arrayBuffer: () => arrayBuffer,
72+
json: () => JSON.parse(arrayBuffer)
73+
};
74+
}
75+
else if (typeof (read) === "function") {
76+
const arrayBuffer = new Uint8Array(read(url, "binary"));
77+
return <Response><any> {
78+
ok: true,
79+
url,
80+
arrayBuffer: () => arrayBuffer,
81+
json: () => JSON.parse(Module.UTF8ArrayToString(arrayBuffer, 0, arrayBuffer.length))
82+
};
83+
}
84+
}
85+
catch (e: any) {
86+
return <Response><any> {
87+
ok: false,
88+
url,
89+
arrayBuffer: () => { throw e; },
90+
json: () => { throw e; }
91+
};
92+
}
93+
throw new Error("No fetch implementation available");
94+
}
95+
5996
function _handle_fetched_asset(ctx: MonoInitContext, asset: AssetEntry, url: string, blob: ArrayBuffer) {
6097
const bytes = new Uint8Array(blob);
6198
if (ctx.tracing)
@@ -143,47 +180,6 @@ function _apply_configuration_from_args(args: MonoConfig) {
143180
mono_wasm_init_coverage_profiler(args.coverage_profiler_options);
144181
}
145182

146-
function _get_fetch_implementation(args: MonoConfig): (asset: string) => Promise<Response> {
147-
if (typeof (args.fetch_file_cb) === "function")
148-
return args.fetch_file_cb;
149-
150-
if (typeof (fetch) === "function") {
151-
return function (asset) {
152-
return fetch(asset, { credentials: "same-origin" });
153-
};
154-
} else if (ENVIRONMENT_IS_NODE || typeof (read) === "function") {
155-
return async function (asset) {
156-
let data: any = null;
157-
let err: any = null;
158-
try {
159-
if (ENVIRONMENT_IS_NODE) {
160-
// eslint-disable-next-line @typescript-eslint/no-var-requires
161-
const fs = require("fs");
162-
data = await fs.promises.readFile(asset);
163-
}
164-
else {
165-
data = read(asset, "binary");
166-
}
167-
}
168-
catch (exc) {
169-
data = null;
170-
err = exc;
171-
}
172-
const res: any = {
173-
ok: !!data,
174-
url: asset,
175-
arrayBuffer: async function () {
176-
if (err) throw err;
177-
return new Uint8Array(data);
178-
}
179-
};
180-
return <Response>res;
181-
};
182-
} else {
183-
throw new Error("No fetch_file_cb was provided and this environment does not expose 'fetch'.");
184-
}
185-
}
186-
187183
function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) {
188184
const moduleExt = Module as EmscriptenModuleMono;
189185

@@ -316,7 +312,7 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise<
316312

317313
_apply_configuration_from_args(args);
318314

319-
const local_fetch = _get_fetch_implementation(args);
315+
const local_fetch = typeof (args.fetch_file_cb) === "function" ? args.fetch_file_cb : _fetch_asset;
320316

321317
const load_asset = async (asset: AllAssetEntryTypes): Promise<void> => {
322318
//TODO we could do module.addRunDependency(asset.name) and delay emscripten run() after all assets are loaded
@@ -392,7 +388,7 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise<
392388
}
393389

394390
// used from Blazor
395-
export function mono_wasm_load_data_archive(data: TypedArray, prefix: string): boolean {
391+
export function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean {
396392
if (data.length < 8)
397393
return false;
398394

@@ -456,20 +452,10 @@ export async function mono_wasm_load_config(configFilePath: string): Promise<voi
456452
const module = Module;
457453
module.addRunDependency(configFilePath);
458454
try {
459-
let config = null;
460455
// NOTE: when we add nodejs make sure to include the nodejs fetch package
461-
if (ENVIRONMENT_IS_WEB) {
462-
const configRaw = await fetch(configFilePath);
463-
config = await configRaw.json();
464-
} else if (ENVIRONMENT_IS_NODE) {
465-
// eslint-disable-next-line @typescript-eslint/no-var-requires
466-
const fs = require("fs");
467-
const json = await fs.promises.readFile(configFilePath);
468-
config = JSON.parse(json);
469-
} else { // shell or worker
470-
const json = read(configFilePath);// read is a v8 debugger command
471-
config = JSON.parse(json);
472-
}
456+
const configRaw = await _fetch_asset(configFilePath);
457+
const config = await configRaw.json();
458+
473459
runtimeHelpers.config = config;
474460
config.environment_variables = config.environment_variables || {};
475461
config.assets = config.assets || [];

src/mono/wasm/runtime/types/emscripten.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ declare interface EmscriptenModule {
5959
setValue(ptr: VoidPtr, value: number, type: string, noSafe?: number | boolean): void;
6060
setValue(ptr: Int32Ptr, value: number, type: string, noSafe?: number | boolean): void;
6161
getValue(ptr: number, type: string, noSafe?: number | boolean): number;
62-
UTF8ToString(arg: CharPtr): string;
63-
UTF8ArrayToString(str: TypedArray, heap: number[] | number, outIdx: number, maxBytesToWrite?: number): string;
62+
UTF8ToString(ptr: CharPtr, maxBytesToRead?: number): string;
63+
UTF8ArrayToString(u8Array: Uint8Array, idx?: number, maxBytesToRead?: number): string;
6464
FS_createPath(parent: string, path: string, canRead?: boolean, canWrite?: boolean): string;
6565
FS_createDataFile(parent: string, name: string, data: TypedArray, canRead: boolean, canWrite: boolean, canOwn?: boolean): string;
6666
removeRunDependency(id: string): void;

0 commit comments

Comments
 (0)