Skip to content

[browser] runtimeConfig via boot config #115113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions eng/testing/scenarios/BuildWasmAppsJobsList.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,5 @@ Wasm.Build.Tests.WorkloadTests
Wasm.Build.Tests.MT.Blazor.SimpleMultiThreadedTests
Wasm.Build.Tests.DebugLevelTests
Wasm.Build.Tests.PreloadingTests
Wasm.Build.Tests.EnvVariablesTests
Wasm.Build.Tests.HttpTests
1 change: 0 additions & 1 deletion src/mono/browser/browser.proj
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,6 @@
"PropertiesThatTriggerRelinking": [
{ "identity": "InvariantTimezone", "defaultValueInRuntimePack": "$(InvariantTimezone)" },
{ "identity": "InvariantGlobalization", "defaultValueInRuntimePack": "$(InvariantGlobalization)" },
{ "identity": "WasmEnableStreamingResponse", "defaultValueInRuntimePack": "$(WasmEnableStreamingResponse)" },
{ "identity": "WasmNativeStrip", "defaultValueInRuntimePack": "$(WasmNativeStrip)" },
{ "identity": "WasmSingleFileBundle", "defaultValueInRuntimePack": "$(WasmSingleFileBundle)" },
{ "identity": "WasmEnableSIMD", "defaultValueInRuntimePack": "$(WasmEnableSIMD)" },
Expand Down
2 changes: 1 addition & 1 deletion src/mono/browser/build/BrowserWasmApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@
WasmIcuDataFileName="$(WasmIcuDataFileName)"
RuntimeAssetsLocation="$(WasmRuntimeAssetsLocation)"
CacheBootResources="$(BlazorCacheBootResources)"
RuntimeConfigJsonPath="$(_WasmRuntimeConfigFilePath)"
RuntimeConfigJsonPath="$(ProjectRuntimeConfigFilePath)"
IsAot="$(RunAOTCompilation)"
IsMultiThreaded="$(WasmEnableThreads)"
>
Expand Down
1 change: 0 additions & 1 deletion src/mono/browser/build/WasmApp.InTree.targets
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<!-- This depends on the root Directory.Build.targets imported this file -->
<UsingTask TaskName="MonoAOTCompiler" AssemblyFile="$(MonoAOTCompilerTasksAssemblyPath)" TaskFactory="TaskHostFactory" />
<UsingTask TaskName="ILStrip" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" TaskFactory="TaskHostFactory" />
<UsingTask TaskName="RuntimeConfigParserTask" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" TaskFactory="TaskHostFactory" />

<!-- TODO: this breaks runtime tests on Helix due to the file not being there for some reason. Once this is fixed we can remove the UpdateRuntimePack target here -->
<Import Project="$(RepositoryEngineeringDir)targetingpacks.targets" Condition="'$(TargetingpacksTargetsImported)' != 'true' and '$(ImportTargetingPacksTargetsInWasmAppTargets)' == 'true'"/>
Expand Down
4 changes: 2 additions & 2 deletions src/mono/browser/runtime/cwraps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const fn_signatures: SigLine[] = [
[true, "mono_wasm_load_icu_data", "number", ["number"]],
[false, "mono_wasm_add_assembly", "number", ["string", "number", "number"]],
[true, "mono_wasm_add_satellite_assembly", "void", ["string", "string", "number", "number"]],
[false, "mono_wasm_load_runtime", null, ["number"]],
[false, "mono_wasm_load_runtime", null, ["number", "number", "number", "number"]],
[true, "mono_wasm_change_debugger_log_level", "void", ["number"]],

[true, "mono_wasm_assembly_load", "number", ["string"]],
Expand Down Expand Up @@ -173,7 +173,7 @@ export interface t_Cwraps {
mono_wasm_load_icu_data(offset: VoidPtr): number;
mono_wasm_add_assembly(name: string, data: VoidPtr, size: number): number;
mono_wasm_add_satellite_assembly(name: string, culture: string, data: VoidPtr, size: number): void;
mono_wasm_load_runtime(debugLevel: number): void;
mono_wasm_load_runtime(debugLevel: number, propertyCount:number, propertyKeys:CharPtrPtr, propertyValues:CharPtrPtr): void;
mono_wasm_change_debugger_log_level(value: number): void;

mono_wasm_assembly_load(name: string): MonoAssembly;
Expand Down
10 changes: 10 additions & 0 deletions src/mono/browser/runtime/dotnet.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,16 @@ type MonoConfig = {
environmentVariables?: {
[i: string]: string;
};
/**
* Subset of runtimeconfig.json
*/
runtimeConfig?: {
runtimeOptions?: {
configProperties?: {
[i: string]: string | number | boolean;
};
};
};
/**
* initial number of workers to add to the emscripten pthread pool
*/
Expand Down
45 changes: 13 additions & 32 deletions src/mono/browser/runtime/driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,6 @@ int mono_regression_test_step (int verbose_level, char *image, char *method_name

static MonoDomain *root_domain;

#define RUNTIMECONFIG_BIN_FILE "runtimeconfig.bin"

extern void mono_wasm_trace_logger (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data);

static void
Expand Down Expand Up @@ -184,7 +182,7 @@ cleanup_runtime_config (MonovmRuntimeConfigArguments *args, void *user_data)
static int runtime_initialized = 0;

EMSCRIPTEN_KEEPALIVE void
mono_wasm_load_runtime (int debug_level)
mono_wasm_load_runtime (int debug_level, int propertyCount, const char **propertyKeys, const char **propertyValues)
{
runtime_initialized = 1;
const char *interp_opts = "";
Expand All @@ -193,34 +191,7 @@ mono_wasm_load_runtime (int debug_level)
mono_wasm_link_icu_shim ();
#endif

// When the list of app context properties changes, please update RuntimeConfigReservedProperties for
// target _WasmGenerateRuntimeConfig in BrowserWasmApp.targets file
const char *appctx_keys[2];
appctx_keys [0] = "APP_CONTEXT_BASE_DIRECTORY";
appctx_keys [1] = "RUNTIME_IDENTIFIER";

const char *appctx_values[2];
appctx_values [0] = "/";
appctx_values [1] = "browser-wasm";

char *file_name = RUNTIMECONFIG_BIN_FILE;
int str_len = strlen (file_name) + 1; // +1 is for the "/"
char *file_path = (char *)malloc (sizeof (char) * (str_len +1)); // +1 is for the terminating null character
int num_char = snprintf (file_path, (str_len + 1), "/%s", file_name);
struct stat buffer;

assert (num_char > 0 && num_char == str_len);

if (stat (file_path, &buffer) == 0) {
MonovmRuntimeConfigArguments *arg = (MonovmRuntimeConfigArguments *)malloc (sizeof (MonovmRuntimeConfigArguments));
arg->kind = 0;
arg->runtimeconfig.name.path = file_path;
monovm_runtimeconfig_initialize (arg, cleanup_runtime_config, file_path);
} else {
free (file_path);
}

monovm_initialize (2, appctx_keys, appctx_values);
monovm_initialize (propertyCount, propertyKeys, propertyValues);

#ifndef INVARIANT_TIMEZONE
char* invariant_timezone = monoeg_g_getenv ("DOTNET_SYSTEM_TIMEZONE_INVARIANT");
Expand All @@ -237,7 +208,17 @@ int initialize_runtime()
{
if (runtime_initialized == 1)
return 0;
mono_wasm_load_runtime (0);

const char *appctx_keys[2];
appctx_keys [0] = "APP_CONTEXT_BASE_DIRECTORY";
appctx_keys [1] = "RUNTIME_IDENTIFIER";

const char *appctx_values[2];
appctx_values [0] = "/";
appctx_values [1] = "browser-wasm";

// this does not support loading runtimeConfig.json part of boot.config.json
mono_wasm_load_runtime (0, 2, appctx_keys, appctx_values);

return 0;
}
Expand Down
42 changes: 38 additions & 4 deletions src/mono/browser/runtime/startup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import { mono_wasm_init_aot_profiler, mono_wasm_init_devtools_profiler, mono_was
import { initialize_marshalers_to_cs } from "./marshal-to-cs";
import { initialize_marshalers_to_js } from "./marshal-to-js";
import { init_polyfills_async } from "./polyfills";
import { strings_init, utf8ToString } from "./strings";
import { strings_init, stringToUTF8Ptr, utf8ToString } from "./strings";
import { init_managed_exports } from "./managed-exports";
import { cwraps_internal } from "./exports-internal";
import { CharPtr, EmscriptenModule, InstantiateWasmCallBack, InstantiateWasmSuccessCallback } from "./types/emscripten";
import { CharPtr, CharPtrPtr, EmscriptenModule, InstantiateWasmCallBack, InstantiateWasmSuccessCallback, VoidPtr } from "./types/emscripten";
import { wait_for_all_assets } from "./assets";
import { replace_linker_placeholders } from "./exports-binding";
import { endMeasure, MeasuredBlock, startMeasure } from "./profiler";
Expand All @@ -28,7 +28,7 @@ import { populateEmscriptenPool, mono_wasm_init_threads } from "./pthreads";
import { currentWorkerThreadEvents, dotnetPthreadCreated, initWorkerThreadEvents, monoThreadInfo } from "./pthreads";
import { mono_wasm_pthread_ptr, update_thread_info } from "./pthreads";
import { jiterpreter_allocate_tables } from "./jiterpreter-support";
import { localHeapViewU8, malloc } from "./memory";
import { localHeapViewU8, malloc, setU32 } from "./memory";
import { assertNoProxies } from "./gc-handles";
import { runtimeList } from "./exports";
import { nativeAbort, nativeExit } from "./run";
Expand Down Expand Up @@ -617,7 +617,41 @@ export function mono_wasm_load_runtime (): void {
if (!loaderHelpers.isDebuggingSupported() || !runtimeHelpers.config.resources!.pdb) {
debugLevel = 0;
}
cwraps.mono_wasm_load_runtime(debugLevel);

const runtimeConfigProperties = new Map<string, string>();
if (runtimeHelpers.config.runtimeConfig?.runtimeOptions?.configProperties) {
for (const [key, value] of Object.entries(runtimeHelpers.config.runtimeConfig?.runtimeOptions?.configProperties)) {
runtimeConfigProperties.set(key, "" + value);
}
}
runtimeConfigProperties.set("APP_CONTEXT_BASE_DIRECTORY", "/");
runtimeConfigProperties.set("RUNTIME_IDENTIFIER", "browser-wasm");
const propertyCount = runtimeConfigProperties.size;

const buffers:VoidPtr[] = [];
const appctx_keys = malloc(4 * runtimeConfigProperties.size) as any as CharPtrPtr;
const appctx_values = malloc(4 * runtimeConfigProperties.size) as any as CharPtrPtr;
buffers.push(appctx_keys as any);
buffers.push(appctx_values as any);

let position = 0;
for (const [key, value] of runtimeConfigProperties.entries()) {
const keyPtr = stringToUTF8Ptr(key);
const valuePtr = stringToUTF8Ptr(value);
setU32((appctx_keys as any) + (position * 4), keyPtr);
setU32((appctx_values as any) + (position * 4), valuePtr);
position++;
buffers.push(keyPtr as any);
buffers.push(valuePtr as any);
}

cwraps.mono_wasm_load_runtime(debugLevel, propertyCount, appctx_keys, appctx_values);

// free the buffers
for (const buffer of buffers) {
Module._free(buffer);
}

endMeasure(mark, MeasuredBlock.loadRuntime);

} catch (err: any) {
Expand Down
10 changes: 10 additions & 0 deletions src/mono/browser/runtime/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ export type MonoConfig = {
environmentVariables?: {
[i: string]: string;
},
/**
* Subset of runtimeconfig.json
*/
runtimeConfig?: {
runtimeOptions?: {
configProperties?: {
[i: string]: string | number | boolean;
}
}
},
/**
* initial number of workers to add to the emscripten pthread pool
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ Copyright (c) .NET Foundation. All rights reserved.
</AddWasmStaticWebAssetsDependsOn>
<GenerateBuildWasmBootJsonDependsOn>
$(GenerateBuildWasmBootJsonDependsOn);
GenerateBuildRuntimeConfigurationFiles;
ResolveWasmOutputs;
</GenerateBuildWasmBootJsonDependsOn>
</PropertyGroup>
Expand Down Expand Up @@ -403,6 +404,7 @@ Copyright (c) .NET Foundation. All rights reserved.
Extensions="@(WasmBootConfigExtension)"
EnvVariables="@(WasmEnvironmentVariable)"
Profilers="$(_WasmProfilers)"
RuntimeConfigJsonPath="$(ProjectRuntimeConfigFilePath)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
ModuleAfterConfigLoaded="@(WasmModuleAfterConfigLoaded)"
ModuleAfterRuntimeReady="@(WasmModuleAfterRuntimeReady)"
Expand Down Expand Up @@ -810,6 +812,7 @@ Copyright (c) .NET Foundation. All rights reserved.
RuntimeOptions="$(_BlazorWebAssemblyRuntimeOptions)"
EnvVariables="@(WasmEnvironmentVariable)"
Profilers="$(_WasmProfilers)"
RuntimeConfigJsonPath="$(ProjectRuntimeConfigFilePath)"
Extensions="@(WasmBootConfigExtension)"
TargetFrameworkVersion="$(TargetFrameworkVersion)"
ModuleAfterConfigLoaded="@(WasmModuleAfterConfigLoaded)"
Expand Down
12 changes: 12 additions & 0 deletions src/mono/wasi/build/WasiApp.props
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,16 @@
</PropertyGroup>

<Import Project="$(WasmCommonTargetsPath)WasmApp.Common.props" />

<PropertyGroup>
<WasmNestedPublishAppDependsOn>
_PrepareForNestedPublish;
$(WasmNestedPublishAppDependsOn);
</WasmNestedPublishAppDependsOn>
<PrepareInputsForWasmBuildDependsOn>
$(PrepareInputsForWasmBuildDependsOn);
_WasmGetRuntimeConfigPath;
</PrepareInputsForWasmBuildDependsOn>
</PropertyGroup>

</Project>
40 changes: 40 additions & 0 deletions src/mono/wasi/build/WasiApp.targets
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
</PrepareForWasmBuildNativeDependsOn>

<WasmLinkDotNetDependsOn>
_WasmGenerateRuntimeConfig;
$(WasmLinkDotNetDependsOn);
_WasiLinkDotNet;
</WasmLinkDotNetDependsOn>

<WasmGenerateAppBundleDependsOn>
$(WasmGenerateAppBundleDependsOn);
_WasmGenerateRuntimeConfig;
_GetWasiGenerateAppBundleDependencies;
_WasiGenerateAppBundle;
_GenerateRunWasmtimeScript;
Expand Down Expand Up @@ -46,6 +48,44 @@
<!--<WasiRunner Condition="'$(WasiRunner)' == ''">wasmtime</WasiRunner>-->
</PropertyGroup>

<Target Name="_WasmGenerateRuntimeConfig"
Inputs="$(_WasmRuntimeConfigFilePath)"
Outputs="$(_ParsedRuntimeConfigFilePath)"
Condition="Exists('$(_WasmRuntimeConfigFilePath)')">
<ItemGroup>
<_RuntimeConfigReservedProperties Include="RUNTIME_IDENTIFIER"/>
<_RuntimeConfigReservedProperties Include="APP_CONTEXT_BASE_DIRECTORY"/>
</ItemGroup>

<RuntimeConfigParserTask
RuntimeConfigFile="$(_WasmRuntimeConfigFilePath)"
OutputFile="$(_ParsedRuntimeConfigFilePath)"
RuntimeConfigReservedProperties="@(_RuntimeConfigReservedProperties)">
</RuntimeConfigParserTask>

<ItemGroup>
<WasmFilesToIncludeInFileSystem Condition="'$(WasmSingleFileBundle)' != 'true'" Include="$(_ParsedRuntimeConfigFilePath)" LoadingStage="Core" />
</ItemGroup>
</Target>

<Target Name="_WasmGetRuntimeConfigPath">
<PropertyGroup>
<_MainAssemblyPath Condition="'%(WasmAssembliesToBundle.FileName)' == '$(AssemblyName)' and '%(WasmAssembliesToBundle.Extension)' == '.dll' and $(WasmGenerateAppBundle) == 'true'">%(WasmAssembliesToBundle.Identity)</_MainAssemblyPath>
<_WasmRuntimeConfigFilePath Condition="'$(_WasmRuntimeConfigFilePath)' == '' and $(_MainAssemblyPath) != ''">$([System.IO.Path]::ChangeExtension($(_MainAssemblyPath), '.runtimeconfig.json'))</_WasmRuntimeConfigFilePath>
<_ParsedRuntimeConfigFilePath Condition="'$(_WasmRuntimeConfigFilePath)' != ''">$([System.IO.Path]::GetDirectoryName($(_WasmRuntimeConfigFilePath)))\runtimeconfig.bin</_ParsedRuntimeConfigFilePath>
</PropertyGroup>
</Target>

<Target Name="_PrepareForNestedPublish" DependsOnTargets="_GetDefaultWasmAssembliesToBundle" Condition="'$(WasmBuildingForNestedPublish)' == 'true'">
<PropertyGroup>
<_WasmRuntimeConfigFilePath Condition="$([System.String]::new(%(PublishItemsOutputGroupOutputs.Identity)).EndsWith('$(AssemblyName).runtimeconfig.json'))">@(PublishItemsOutputGroupOutputs)</_WasmRuntimeConfigFilePath>
</PropertyGroup>

<PropertyGroup Condition="'$(_WasmRuntimeConfigFilePath)' == ''">
<_WasmRuntimeConfigFilePath Condition="$([System.String]::new(%(PublishItemsOutputGroupOutputs.Identity)).EndsWith('$(AssemblyName).runtimeconfig.json'))">@(PublishItemsOutputGroupOutputs)</_WasmRuntimeConfigFilePath>
</PropertyGroup>
</Target>

<Target Name="_GetWasiGenerateAppBundleDependencies">
<ItemGroup Condition="'$(InvariantGlobalization)' == 'true' or '$(WasmSingleFileBundle)' == 'true'">
<ReferenceCopyLocalPaths Remove="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)icudt.dat" />
Expand Down
36 changes: 36 additions & 0 deletions src/mono/wasm/Wasm.Build.Tests/HttpTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using Xunit.Abstractions;
using Xunit;

#nullable enable

namespace Wasm.Build.Tests;

public class HttpTests : WasmTemplateTestsBase
{
public HttpTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext)
: base(output, buildContext)
{
}

[Fact]
// testing that WasmEnableStreamingResponse=false MSbuild prop is passed to the app and HTTP behaves as expected
public async Task HttpNoStreamingTest()
{
Configuration config = Configuration.Release;
ProjectInfo info = CopyTestAsset(config, false, TestAsset.WasmBasicTestApp, "HttpTest");

BuildProject(info, config, new BuildOptions(ExtraMSBuildArgs: "-p:WasmEnableStreamingResponse=false",AssertAppBundle: false), isNativeBuild: false);

var result = await RunForBuildWithDotnetRun(new BrowserRunOptions(Configuration: config, TestScenario: "HttpNoStreamingTest"));
Assert.Contains("AppContext WasmEnableStreamingResponse=false", result.TestOutput);
Assert.Contains("baz=boo", result.TestOutput);
}
}
1 change: 0 additions & 1 deletion src/mono/wasm/build/WasmApp.Common.props
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
</_WasmBuildAppCoreDependsOn>

<WasmNestedPublishAppDependsOn>
_PrepareForNestedPublish;
_WasmBuildAppCore;
</WasmNestedPublishAppDependsOn>
</PropertyGroup>
Expand Down
Loading
Loading