22// The .NET Foundation licenses this file to you under the MIT license.
33
44import { INTERNAL , Module , MONO , runtimeHelpers } from "./modules" ;
5- import { AssetEntry , CharPtr , CharPtrNull , EmscriptenModuleMono , GlobalizationMode , MonoConfig , TypedArray , VoidPtr , wasm_type_symbol } from "./types" ;
5+ import { AllAssetEntryTypes , AssetEntry , CharPtr , CharPtrNull , EmscriptenModuleMono , GlobalizationMode , MonoConfig , TypedArray , VoidPtr , wasm_type_symbol } from "./types" ;
66import cwraps from "./cwraps" ;
77import { mono_wasm_raise_debug_event , mono_wasm_runtime_ready } from "./debug" ;
88import { mono_wasm_globalization_init , mono_wasm_load_icu_data } from "./icu" ;
@@ -56,7 +56,7 @@ export function mono_wasm_set_runtime_options(options: string[]): void {
5656 cwraps . mono_wasm_parse_runtime_options ( options . length , argv ) ;
5757}
5858
59- function _handle_loaded_asset ( ctx : MonoInitContext , asset : AssetEntry , url : string , blob : ArrayBuffer ) {
59+ function _handle_fetched_asset ( ctx : MonoInitContext , asset : AssetEntry , url : string , blob : ArrayBuffer ) {
6060 const bytes = new Uint8Array ( blob ) ;
6161 if ( ctx . tracing )
6262 console . log ( `MONO_WASM: Loaded:${ asset . name } as ${ asset . behavior } size ${ bytes . length } from ${ url } ` ) ;
@@ -129,16 +129,6 @@ function _handle_loaded_asset(ctx: MonoInitContext, asset: AssetEntry, url: stri
129129 }
130130}
131131
132- // Initializes the runtime and loads assemblies, debug information, and other files.
133- export function mono_load_runtime_and_bcl_args ( args : MonoConfig ) : void {
134- try {
135- return _load_assets_and_runtime ( args ) ;
136- } catch ( exc : any ) {
137- console . error ( "MONO_WASM: Error in mono_load_runtime_and_bcl_args:" , exc ) ;
138- throw exc ;
139- }
140- }
141-
142132function _apply_configuration_from_args ( args : MonoConfig ) {
143133 for ( const k in ( args . environment_variables || { } ) )
144134 mono_wasm_setenv ( k , args . environment_variables ! [ k ] ) ;
@@ -153,7 +143,7 @@ function _apply_configuration_from_args(args: MonoConfig) {
153143 mono_wasm_init_coverage_profiler ( args . coverage_profiler_options ) ;
154144}
155145
156- function _get_fetch_file_cb_from_args ( args : MonoConfig ) : ( asset : string ) => Promise < Response > {
146+ function _get_fetch_implementation ( args : MonoConfig ) : ( asset : string ) => Promise < Response > {
157147 if ( typeof ( args . fetch_file_cb ) === "function" )
158148 return args . fetch_file_cb ;
159149
@@ -307,136 +297,101 @@ export function bindings_lazy_init(): void {
307297
308298 _create_primitive_converters ( ) ;
309299}
310- function _load_assets_and_runtime ( args : MonoConfig ) {
311- if ( args . enable_debugging )
312- args . debug_level = args . enable_debugging ;
313-
314- const ctx : MonoInitContext = {
315- tracing : args . diagnostic_tracing || false ,
316- pending_count : args . assets . length ,
317- loaded_assets : Object . create ( null ) ,
318- // dlls and pdbs, used by blazor and the debugger
319- loaded_files : [ ] ,
320- createPath : Module . FS_createPath ,
321- createDataFile : Module . FS_createDataFile
322- } ;
323-
324- if ( ctx . tracing )
325- console . log ( "MONO_WASM: mono_wasm_load_runtime_with_args" , JSON . stringify ( args ) ) ;
326-
327- _apply_configuration_from_args ( args ) ;
328300
329- const fetch_file_cb = _get_fetch_file_cb_from_args ( args ) ;
330-
331- const onPendingRequestComplete = function ( ) {
332- -- ctx . pending_count ;
333-
334- if ( ctx . pending_count === 0 ) {
335- try {
336- _finalize_startup ( args , ctx ) ;
337- } catch ( exc : any ) {
338- console . error ( "MONO_WASM: Unhandled exception in _finalize_startup" , exc ) ;
339- console . error ( exc . stack ) ;
340- throw exc ;
341- }
342- }
343- } ;
301+ // Initializes the runtime and loads assemblies, debug information, and other files.
302+ export async function mono_load_runtime_and_bcl_args ( args : MonoConfig ) : Promise < void > {
303+ try {
304+ if ( args . enable_debugging )
305+ args . debug_level = args . enable_debugging ;
306+
307+ const ctx : MonoInitContext = {
308+ tracing : args . diagnostic_tracing || false ,
309+ pending_count : args . assets . length ,
310+ loaded_assets : Object . create ( null ) ,
311+ // dlls and pdbs, used by blazor and the debugger
312+ loaded_files : [ ] ,
313+ createPath : Module . FS_createPath ,
314+ createDataFile : Module . FS_createDataFile
315+ } ;
344316
345- const processFetchResponseBuffer = function ( asset : AssetEntry , url : string , buffer : ArrayBuffer ) {
346- try {
347- _handle_loaded_asset ( ctx , asset , url , buffer ) ;
348- } catch ( exc ) {
349- console . error ( `MONO_WASM: Unhandled exception in processFetchResponseBuffer ${ url } ${ exc } ` ) ;
350- throw exc ;
351- } finally {
352- onPendingRequestComplete ( ) ;
353- }
354- } ;
317+ _apply_configuration_from_args ( args ) ;
355318
356- args . assets . forEach ( function ( asset : AssetEntry ) {
357- let sourceIndex = 0 ;
358- const sourcesList = asset . load_remote ? args . remote_sources ! : [ "" ] ;
319+ const local_fetch = _get_fetch_implementation ( args ) ;
359320
360- const handleFetchResponse = function ( response : Response ) {
361- if ( ! response . ok ) {
362- try {
363- attemptNextSource ( ) ;
364- return ;
365- } catch ( exc ) {
366- console . error ( `MONO_WASM: Unhandled exception in handleFetchResponse attemptNextSource for asset ${ asset . name } ${ exc } ` ) ;
367- throw exc ;
368- }
369- }
321+ const load_asset = async ( asset : AllAssetEntryTypes ) : Promise < void > => {
322+ //TODO we could do module.addRunDependency(asset.name) and delay emscripten run() after all assets are loaded
370323
371- try {
372- const bufferPromise = response . arrayBuffer ( ) ;
373- bufferPromise . then ( ( data ) => processFetchResponseBuffer ( asset , response . url , data ) ) ;
374- } catch ( exc ) {
375- console . error ( `MONO_WASM: Unhandled exception in handleFetchResponse for asset ${ asset . name } ${ exc } ` ) ;
376- attemptNextSource ( ) ;
377- }
378- } ;
324+ const sourcesList = asset . load_remote ? args . remote_sources ! : [ "" ] ;
325+ let error = undefined ;
326+ for ( let sourcePrefix of sourcesList ) {
327+ // HACK: Special-case because MSBuild doesn't allow "" as an attribute
328+ if ( sourcePrefix === "./" )
329+ sourcePrefix = "" ;
379330
380- const attemptNextSource = function ( ) {
381- if ( sourceIndex >= sourcesList . length ) {
382- const msg = `MONO_WASM: Failed to load ${ asset . name } ` ;
383- try {
384- const isOk = asset . is_optional ||
385- ( asset . name . match ( / \. p d b $ / ) && args . ignore_pdb_load_errors ) ;
386-
387- if ( isOk )
388- console . debug ( msg ) ;
389- else {
390- console . error ( msg ) ;
391- throw new Error ( msg ) ;
331+ let attemptUrl ;
332+ if ( sourcePrefix . trim ( ) === "" ) {
333+ if ( asset . behavior === "assembly" )
334+ attemptUrl = locateFile ( args . assembly_root + "/" + asset . name ) ;
335+ else if ( asset . behavior === "resource" ) {
336+ const path = asset . culture !== "" ? `${ asset . culture } /${ asset . name } ` : asset . name ;
337+ attemptUrl = locateFile ( args . assembly_root + "/" + path ) ;
392338 }
393- } finally {
394- onPendingRequestComplete ( ) ;
395- }
396- }
397-
398- let sourcePrefix = sourcesList [ sourceIndex ] ;
399- sourceIndex ++ ;
400-
401- // HACK: Special-case because MSBuild doesn't allow "" as an attribute
402- if ( sourcePrefix === "./" )
403- sourcePrefix = "" ;
404-
405- let attemptUrl ;
406- if ( sourcePrefix . trim ( ) === "" ) {
407- if ( asset . behavior === "assembly" )
408- attemptUrl = locateFile ( args . assembly_root + "/" + asset . name ) ;
409- else if ( asset . behavior === "resource" ) {
410- const path = asset . culture !== "" ? `${ asset . culture } /${ asset . name } ` : asset . name ;
411- attemptUrl = locateFile ( args . assembly_root + "/" + path ) ;
339+ else
340+ attemptUrl = asset . name ;
341+ } else {
342+ attemptUrl = sourcePrefix + asset . name ;
412343 }
413- else
414- attemptUrl = asset . name ;
415- } else {
416- attemptUrl = sourcePrefix + asset . name ;
417- }
418-
419- try {
420344 if ( asset . name === attemptUrl ) {
421345 if ( ctx . tracing )
422346 console . log ( `MONO_WASM: Attempting to fetch '${ attemptUrl } '` ) ;
423347 } else {
424348 if ( ctx . tracing )
425349 console . log ( `MONO_WASM: Attempting to fetch '${ attemptUrl } ' for ${ asset . name } ` ) ;
426350 }
427- const fetch_promise = fetch_file_cb ( attemptUrl ) ;
428- fetch_promise . then ( handleFetchResponse ) ;
429- } catch ( exc ) {
430- console . error ( `MONO_WASM: Error fetching ${ attemptUrl } ${ exc } ` ) ;
431- attemptNextSource ( ) ;
351+ try {
352+ const response = await local_fetch ( attemptUrl ) ;
353+ if ( ! response . ok ) {
354+ error = new Error ( `MONO_WASM: Fetch '${ attemptUrl } ' for ${ asset . name } failed ${ response . status } ${ response . statusText } ` ) ;
355+ continue ; // next source
356+ }
357+
358+ const buffer = await response . arrayBuffer ( ) ;
359+ _handle_fetched_asset ( ctx , asset , attemptUrl , buffer ) ;
360+ -- ctx . pending_count ;
361+ error = undefined ;
362+ }
363+ catch ( err ) {
364+ error = new Error ( `MONO_WASM: Fetch '${ attemptUrl } ' for ${ asset . name } failed ${ err } ` ) ;
365+ continue ; //next source
366+ }
367+
368+ if ( ! error ) {
369+ //TODO Module.removeRunDependency(configFilePath);
370+ break ; // this source worked, stop searching
371+ }
372+ }
373+ if ( error ) {
374+ const isOkToFail = asset . is_optional || ( asset . name . match ( / \. p d b $ / ) && args . ignore_pdb_load_errors ) ;
375+ if ( ! isOkToFail )
376+ throw error ;
432377 }
433378 } ;
379+ const fetch_promises : Promise < void > [ ] = [ ] ;
380+ // start fetching all assets in parallel
381+ for ( const asset of args . assets ) {
382+ fetch_promises . push ( load_asset ( asset ) ) ;
383+ }
434384
435- attemptNextSource ( ) ;
436- } ) ;
385+ await Promise . all ( fetch_promises ) ;
386+
387+ _finalize_startup ( args , ctx ) ;
388+ } catch ( exc : any ) {
389+ console . error ( "MONO_WASM: Error in mono_load_runtime_and_bcl_args:" , exc ) ;
390+ throw exc ;
391+ }
437392}
438393
439- // used from ASP.NET
394+ // used from Blazor
440395export function mono_wasm_load_data_archive ( data : TypedArray , prefix : string ) : boolean {
441396 if ( data . length < 8 )
442397 return false ;
0 commit comments