Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/mono/browser/runtime/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ interface DotnetHostBuilder {
* Sets a callback that is invoked after each resource finishes downloading.
*/
withDownloadResourceProgress(callback?: (resourcesLoaded: number, totalResources: number) => void): DotnetHostBuilder;
/**
* Sets a callback that is invoked after the runtime configuration is loaded.
*/
withConfigLoaded(callback?: (config: MonoConfig) => void | Promise<void>): DotnetHostBuilder;
/**
* Overrides the built-in boot resource loading mechanism so that boot resources can be fetched
* from a custom source, such as an external CDN.
Expand Down Expand Up @@ -446,9 +450,6 @@ declare const enum GlobalizationMode {
}
type DotnetModuleConfig = {
config?: MonoConfig;
onConfigLoaded?: (config: MonoConfig) => void | Promise<void>;
onDotnetReady?: () => void | Promise<void>;
onDownloadResourceProgress?: (resourcesLoaded: number, totalResources: number) => void;
imports?: any;
exports?: string[];
} & Partial<EmscriptenModule>;
Expand Down
4 changes: 2 additions & 2 deletions src/mono/browser/runtime/loader/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { mono_exit } from "./exit";
import { getIcuResourceName } from "./icu";
import { makeURLAbsoluteWithApplicationBase } from "./polyfills";
import { mono_log_info } from "./logging";
import { loaderCallbacks } from "./callbacks";


let throttlingPromise: PromiseAndController<void> | undefined;
Expand Down Expand Up @@ -628,8 +629,7 @@ function download_resource (asset: AssetEntryInternal): LoadingResource {
}

resourcesLoaded++;
if (loaderHelpers.onDownloadResourceProgress)
loaderHelpers.onDownloadResourceProgress(resourcesLoaded, totalResources.size);
loaderCallbacks.downloadResourceProgress?.(resourcesLoaded, totalResources.size);
});
return response;
} catch (err) {
Expand Down
40 changes: 40 additions & 0 deletions src/mono/browser/runtime/loader/callbacks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { MonoConfig, RuntimeAPI } from "../types";

export const loaderCallbacks: {
configLoaded?: (config: MonoConfig, api: RuntimeAPI) => void | Promise<void>;
dotnetReady?: () => void | Promise<void>;
downloadResourceProgress?: (resourcesLoaded: number, totalResources: number) => void;
} = {};

type LegacyModuleCallbacks = {
onConfigLoaded?: (config: MonoConfig, api: RuntimeAPI) => void | Promise<void>;
onDotnetReady?: () => void | Promise<void>;
onDownloadResourceProgress?: (resourcesLoaded: number, totalResources: number) => void;
};

/**
* Moves the legacy `Module` callbacks into the loader state, so that they are never stored on the Emscripten module.
* Returns a copy of the configuration without those callbacks, which can be merged into the Emscripten module.
*/
export function extractLegacyModuleCallbacks<T extends object> (moduleConfig: T): T {
const legacy = moduleConfig as LegacyModuleCallbacks;
if (!legacy || (legacy.onConfigLoaded === undefined && legacy.onDotnetReady === undefined && legacy.onDownloadResourceProgress === undefined)) {
return moduleConfig;
}

const { onConfigLoaded, onDotnetReady, onDownloadResourceProgress, ...rest } = moduleConfig as T & LegacyModuleCallbacks;
if (onConfigLoaded !== undefined) {
loaderCallbacks.configLoaded = onConfigLoaded;
}
if (onDotnetReady !== undefined) {
loaderCallbacks.dotnetReady = onDotnetReady;
}
if (onDownloadResourceProgress !== undefined) {
loaderCallbacks.downloadResourceProgress = onDownloadResourceProgress;
}

return rest as unknown as T;
}
15 changes: 6 additions & 9 deletions src/mono/browser/runtime/loader/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { mono_log_error, mono_log_debug } from "./logging";
import { importLibraryInitializers, invokeLibraryInitializers } from "./libraryInitializers";
import { mono_exit } from "./exit";
import { browserVirtualAppBase } from "./globals";
import { loaderCallbacks } from "./callbacks";

export function deep_merge_config (target: MonoConfigInternal, source: MonoConfigInternal): MonoConfigInternal {
// no need to merge the same object
Expand Down Expand Up @@ -240,14 +241,11 @@ export async function mono_wasm_load_config (module: DotnetModuleInternal): Prom
await importLibraryInitializers(loaderHelpers.config.resources?.modulesAfterConfigLoaded);
await invokeLibraryInitializers("onRuntimeConfigLoaded", [loaderHelpers.config]);

if (module.onConfigLoaded) {
try {
await module.onConfigLoaded(loaderHelpers.config, exportedRuntimeAPI);
normalizeConfig();
} catch (err: any) {
mono_log_error("onConfigLoaded() failed", err);
throw err;
}
try {
await loaderCallbacks.configLoaded?.(loaderHelpers.config, exportedRuntimeAPI);
} catch (err: any) {
mono_log_error("onConfigLoaded() failed", err);
throw err;
}

normalizeConfig();
Expand All @@ -268,4 +266,3 @@ export function isDebuggingSupported (): boolean {

return loaderHelpers.isChromium || loaderHelpers.isFirefox;
}

5 changes: 1 addition & 4 deletions src/mono/browser/runtime/loader/polyfills.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

import WasmEnableThreads from "consts:wasmEnableThreads";

import type { DotnetModuleInternal } from "../types/internal";
import { ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_SHELL, loaderHelpers, ENVIRONMENT_IS_WEB, mono_assert } from "./globals";

let node_fs: any | undefined = undefined;
Expand Down Expand Up @@ -34,7 +33,7 @@ export function verifyEnvironment () {
}
}

export async function detect_features_and_polyfill (module: DotnetModuleInternal): Promise<void> {
export async function detect_features_and_polyfill (): Promise<void> {
if (ENVIRONMENT_IS_SHELL) {
if (typeof globalThis.atob !== "function") {
const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
Expand Down Expand Up @@ -81,8 +80,6 @@ export async function detect_features_and_polyfill (module: DotnetModuleInternal
loaderHelpers.out = console.log;
// eslint-disable-next-line no-console
loaderHelpers.err = console.error;
loaderHelpers.onDownloadResourceProgress = module.onDownloadResourceProgress;

if (ENVIRONMENT_IS_WEB && globalThis.navigator) {
const navigator: any = globalThis.navigator;
const brands = navigator.userAgentData && navigator.userAgentData.brands;
Expand Down
31 changes: 25 additions & 6 deletions src/mono/browser/runtime/loader/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { runtimeHelpers, loaderHelpers } from "./globals";
import { init_globalization } from "./icu";
import { setupPreloadChannelToMainThread } from "./worker";
import { importLibraryInitializers, invokeLibraryInitializers } from "./libraryInitializers";
import { extractLegacyModuleCallbacks, loaderCallbacks } from "./callbacks";


export class HostBuilder implements DotnetHostBuilder {
Expand All @@ -24,7 +25,7 @@ export class HostBuilder implements DotnetHostBuilder {
// internal
withModuleConfig (moduleConfig: DotnetModuleConfig): DotnetHostBuilder {
try {
deep_merge_module(emscriptenModule, moduleConfig);
deep_merge_module(emscriptenModule, extractLegacyModuleCallbacks(moduleConfig));
return this;
} catch (err) {
mono_exit(1, err);
Expand Down Expand Up @@ -217,9 +218,27 @@ export class HostBuilder implements DotnetHostBuilder {

withDownloadResourceProgress (callback?: (resourcesLoaded: number, totalResources: number) => void): DotnetHostBuilder {
try {
deep_merge_module(emscriptenModule, {
onDownloadResourceProgress: callback
});
loaderCallbacks.downloadResourceProgress = callback;
return this;
} catch (err) {
mono_exit(1, err);
throw err;
}
}

withConfigLoaded (callback?: (config: MonoConfig) => void | Promise<void>): DotnetHostBuilder {
try {
loaderCallbacks.configLoaded = callback;
return this;
} catch (err) {
mono_exit(1, err);
throw err;
}
}

withDotnetReady (callback?: () => void | Promise<void>): DotnetHostBuilder {
try {
loaderCallbacks.dotnetReady = callback;
return this;
} catch (err) {
mono_exit(1, err);
Expand Down Expand Up @@ -320,7 +339,7 @@ async function prepareEmscripten (moduleFactory: DotnetModuleConfig | ((api: Run
throw new Error("Can't use moduleFactory callback of createDotnetRuntime function.");
}

await detect_features_and_polyfill(emscriptenModule);
await detect_features_and_polyfill();
}

export async function createEmscripten (moduleFactory: DotnetModuleConfig | ((api: RuntimeAPI) => DotnetModuleConfig)): Promise<RuntimeAPI | EmscriptenModuleInternal> {
Expand Down Expand Up @@ -474,7 +493,7 @@ async function createEmscriptenWorker (): Promise<EmscriptenModuleInternal> {
setup_proxy_console("main", globalThis.console, globalThis.location.origin);
}

await detect_features_and_polyfill(emscriptenModule);
await detect_features_and_polyfill();

await mono_download_assets();

Expand Down
13 changes: 6 additions & 7 deletions src/mono/browser/runtime/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { replace_linker_placeholders } from "./exports-binding";
import { endMeasure, MeasuredBlock, startMeasure } from "./profiler";
import { interp_pgo_load_data, interp_pgo_save_data } from "./interp-pgo";
import { mono_log_debug, mono_log_error, mono_log_info, mono_log_warn } from "./logging";
import { loaderCallbacks } from "./loader/callbacks";

// threads
import { populateEmscriptenPool, mono_wasm_init_threads } from "./pthreads";
Expand Down Expand Up @@ -356,13 +357,11 @@ export function postRunWorker () {
async function mono_wasm_after_user_runtime_initialized (): Promise<void> {
mono_log_debug("mono_wasm_after_user_runtime_initialized");
try {
if (Module.onDotnetReady) {
try {
await Module.onDotnetReady();
} catch (err: any) {
mono_log_error("onDotnetReady () failed", err);
throw err;
}
try {
await loaderCallbacks.dotnetReady?.();
} catch (err: any) {
mono_log_error("onDotnetReady () failed", err);
throw err;
}
} catch (err: any) {
mono_log_error("mono_wasm_after_user_runtime_initialized () failed", err);
Expand Down
8 changes: 4 additions & 4 deletions src/mono/browser/runtime/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ export interface DotnetHostBuilder {
* Sets a callback that is invoked after each resource finishes downloading.
*/
withDownloadResourceProgress(callback?: (resourcesLoaded: number, totalResources: number) => void): DotnetHostBuilder;
/**
* Sets a callback that is invoked after the runtime configuration is loaded.
*/
withConfigLoaded(callback?: (config: MonoConfig) => void | Promise<void>): DotnetHostBuilder;
/**
* Overrides the built-in boot resource loading mechanism so that boot resources can be fetched
* from a custom source, such as an external CDN.
Expand Down Expand Up @@ -475,10 +479,6 @@ export const enum GlobalizationMode {

export type DotnetModuleConfig = {
config?: MonoConfig,
onConfigLoaded?: (config: MonoConfig) => void | Promise<void>;
onDotnetReady?: () => void | Promise<void>;
onDownloadResourceProgress?: (resourcesLoaded: number, totalResources: number) => void;

imports?: any;
exports?: string[];
} & Partial<EmscriptenModule>
Expand Down
2 changes: 0 additions & 2 deletions src/mono/browser/runtime/types/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,6 @@ export type LoaderHelpers = {
err(message: string): void;

retrieve_asset_download(asset: AssetEntry): Promise<ArrayBuffer>;
onDownloadResourceProgress?: (resourcesLoaded: number, totalResources: number) => void;
installUnhandledErrorHandler: () => void;

loadBootResource?: LoadBootResourceCallback;
Expand Down Expand Up @@ -445,7 +444,6 @@ export declare interface EmscriptenModuleInternal {
getWasmTableEntry(index: number): any;
removeRunDependency(id: string): void;
addRunDependency(id: string): void;
onConfigLoaded?: (config: MonoConfig, api: RuntimeAPI) => void | Promise<void>;
safeSetTimeout(func: Function, timeout: number): number;
runtimeKeepalivePush(): void;
runtimeKeepalivePop(): void;
Expand Down
6 changes: 2 additions & 4 deletions src/mono/browser/test-main.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -271,10 +271,8 @@ function configureRuntime(dotnet, runArgs) {

const modulesToLoad = runArgs.environmentVariables["NPM_MODULES"];
if (modulesToLoad) {
dotnet.withModuleConfig({
onConfigLoaded: async (config) => {
await loadNodeModules(config, modulesToLoad)
}
dotnet.withConfigLoaded(async (config) => {
await loadNodeModules(config, modulesToLoad)
})
}
}
Expand Down
28 changes: 14 additions & 14 deletions src/mono/sample/wasm/browser-advanced/wwwroot/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,28 +44,28 @@ try {
}]
}
})
.withConfigLoaded((config) => {
// This is called during emscripten `dotnet.wasm` instantiation, after we fetched config.
console.log('user code onConfigLoaded');
// config is loaded and could be tweaked before the rest of the runtime startup sequence
config.environmentVariables["MONO_LOG_LEVEL"] = "debug";
config.browserProfilerOptions = {
sampleIntervalMs: 5.15,
callSpec: "N:Sample" // needs to match AOT profile
};
})
.withDotnetReady(() => {
// This is called after all assets are loaded.
console.log('user code onDotnetReady');
})
.withModuleConfig({
onConfigLoaded: (config) => {
// This is called during emscripten `dotnet.wasm` instantiation, after we fetched config.
console.log('user code Module.onConfigLoaded');
// config is loaded and could be tweaked before the rest of the runtime startup sequence
config.environmentVariables["MONO_LOG_LEVEL"] = "debug";
config.browserProfilerOptions = {
sampleIntervalMs: 5.15,
callSpec: "N:Sample" // needs to match AOT profile
};
},
preInit: [() => { console.log('user code Module.preInit'); }],
preRun: [() => { console.log('user code Module.preRun'); }],
onRuntimeInitialized: () => {
console.log('user code Module.onRuntimeInitialized');
// here we could use API passed into this callback
// Module.FS.chdir("/");
},
onDotnetReady: () => {
// This is called after all assets are loaded.
console.log('user code Module.onDotnetReady');
},
postRun: [() => { console.log('user code Module.postRun'); }],
out: (text) => { console.log("ADVANCED:" + text) },
})
Expand Down
12 changes: 5 additions & 7 deletions src/mono/sample/wasm/browser-shutdown/wwwroot/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,11 @@ try {
const { setModuleImports, getAssemblyExports, getConfig } = await dotnet
.withModuleConfig()
.withConfig({ appendElementOnExit: true, exitOnUnhandledError: true, logExitCode: true })
.withModuleConfig({
onConfigLoaded: () => {
// you can test abort of the startup by opening http://localhost:8000/?throwError=true
const params = new URLSearchParams(location.search);
if (params.get("throwError") === "true") {
throw new Error("Error thrown from OnConfigLoaded");
}
.withConfigLoaded(() => {
// you can test abort of the startup by opening http://localhost:8000/?throwError=true
const params = new URLSearchParams(location.search);
if (params.get("throwError") === "true") {
throw new Error("Error thrown from OnConfigLoaded");
}
})
.create();
Expand Down
Loading
Loading