From 2b1f420cca78ca03f867caa68f30cf81ae2b4187 Mon Sep 17 00:00:00 2001 From: Larry Ewing Date: Tue, 16 Nov 2021 12:06:25 -0600 Subject: [PATCH] [wasm] Rework fetch (#61639) * Unify some code and load mono-config.json using our _fetch_asset --- src/mono/wasm/runtime/startup.ts | 100 +++++++++----------- src/mono/wasm/runtime/types/emscripten.d.ts | 4 +- 2 files changed, 45 insertions(+), 59 deletions(-) diff --git a/src/mono/wasm/runtime/startup.ts b/src/mono/wasm/runtime/startup.ts index df61a27399d..dcab05fefeb 100644 --- a/src/mono/wasm/runtime/startup.ts +++ b/src/mono/wasm/runtime/startup.ts @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. import { INTERNAL, Module, MONO, runtimeHelpers } from "./modules"; -import { AllAssetEntryTypes, AssetEntry, CharPtr, CharPtrNull, EmscriptenModuleMono, GlobalizationMode, MonoConfig, TypedArray, VoidPtr, wasm_type_symbol } from "./types"; +import { AllAssetEntryTypes, AssetEntry, CharPtr, CharPtrNull, EmscriptenModuleMono, GlobalizationMode, MonoConfig, VoidPtr, wasm_type_symbol } from "./types"; import cwraps from "./cwraps"; import { mono_wasm_raise_debug_event, mono_wasm_runtime_ready } from "./debug"; 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 { cwraps.mono_wasm_parse_runtime_options(options.length, argv); } +async function _fetch_asset(url: string): Promise { + try { + if (typeof (fetch) === "function") { + return fetch(url, { credentials: "same-origin" }); + } + else if (ENVIRONMENT_IS_NODE) { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const fs = require("fs"); + const arrayBuffer = await fs.promises.readFile(url); + return { + ok: true, + url, + arrayBuffer: () => arrayBuffer, + json: () => JSON.parse(arrayBuffer) + }; + } + else if (typeof (read) === "function") { + const arrayBuffer = new Uint8Array(read(url, "binary")); + return { + ok: true, + url, + arrayBuffer: () => arrayBuffer, + json: () => JSON.parse(Module.UTF8ArrayToString(arrayBuffer, 0, arrayBuffer.length)) + }; + } + } + catch (e: any) { + return { + ok: false, + url, + arrayBuffer: () => { throw e; }, + json: () => { throw e; } + }; + } + throw new Error("No fetch implementation available"); +} + function _handle_fetched_asset(ctx: MonoInitContext, asset: AssetEntry, url: string, blob: ArrayBuffer) { const bytes = new Uint8Array(blob); if (ctx.tracing) @@ -143,47 +180,6 @@ function _apply_configuration_from_args(args: MonoConfig) { mono_wasm_init_coverage_profiler(args.coverage_profiler_options); } -function _get_fetch_implementation(args: MonoConfig): (asset: string) => Promise { - if (typeof (args.fetch_file_cb) === "function") - return args.fetch_file_cb; - - if (typeof (fetch) === "function") { - return function (asset) { - return fetch(asset, { credentials: "same-origin" }); - }; - } else if (ENVIRONMENT_IS_NODE || typeof (read) === "function") { - return async function (asset) { - let data: any = null; - let err: any = null; - try { - if (ENVIRONMENT_IS_NODE) { - // eslint-disable-next-line @typescript-eslint/no-var-requires - const fs = require("fs"); - data = await fs.promises.readFile(asset); - } - else { - data = read(asset, "binary"); - } - } - catch (exc) { - data = null; - err = exc; - } - const res: any = { - ok: !!data, - url: asset, - arrayBuffer: async function () { - if (err) throw err; - return new Uint8Array(data); - } - }; - return res; - }; - } else { - throw new Error("No fetch_file_cb was provided and this environment does not expose 'fetch'."); - } -} - function _finalize_startup(args: MonoConfig, ctx: MonoInitContext) { const moduleExt = Module as EmscriptenModuleMono; @@ -316,7 +312,7 @@ export async function mono_load_runtime_and_bcl_args(args: MonoConfig): Promise< _apply_configuration_from_args(args); - const local_fetch = _get_fetch_implementation(args); + const local_fetch = typeof (args.fetch_file_cb) === "function" ? args.fetch_file_cb : _fetch_asset; const load_asset = async (asset: AllAssetEntryTypes): Promise => { //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< } // used from Blazor -export function mono_wasm_load_data_archive(data: TypedArray, prefix: string): boolean { +export function mono_wasm_load_data_archive(data: Uint8Array, prefix: string): boolean { if (data.length < 8) return false; @@ -456,20 +452,10 @@ export async function mono_wasm_load_config(configFilePath: string): Promise