stabilizaiton work - projects rework for maintenanceability and ui livening
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
// SPDX-License-Identifier: BUSL-1.1
|
||||
// Copyright (c) 2025 StellaOps
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using StellaOps.Platform.WebService.Options;
|
||||
|
||||
namespace StellaOps.Platform.WebService.Services;
|
||||
|
||||
/// <summary>
|
||||
/// Composes a final <see cref="PlatformEnvironmentSettingsOptions"/> from three layers:
|
||||
/// <list type="number">
|
||||
/// <item>Environment variables (via <see cref="Configuration.StellaOpsEnvVarPostConfigure"/>)</item>
|
||||
/// <item>YAML/JSON configuration (standard IOptions binding)</item>
|
||||
/// <item>Database (via <see cref="IEnvironmentSettingsStore"/>)</item>
|
||||
/// </list>
|
||||
/// Layer 3 (DB) has highest priority and is overlaid last.
|
||||
/// </summary>
|
||||
public sealed class EnvironmentSettingsComposer
|
||||
{
|
||||
private readonly IOptionsMonitor<PlatformServiceOptions> _optionsMonitor;
|
||||
private readonly IEnvironmentSettingsStore _store;
|
||||
|
||||
public EnvironmentSettingsComposer(
|
||||
IOptionsMonitor<PlatformServiceOptions> optionsMonitor,
|
||||
IEnvironmentSettingsStore store)
|
||||
{
|
||||
_optionsMonitor = optionsMonitor ?? throw new ArgumentNullException(nameof(optionsMonitor));
|
||||
_store = store ?? throw new ArgumentNullException(nameof(store));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the merged environment settings with all three layers applied.
|
||||
/// </summary>
|
||||
public async Task<PlatformEnvironmentSettingsOptions> ComposeAsync(CancellationToken ct = default)
|
||||
{
|
||||
var source = _optionsMonitor.CurrentValue.EnvironmentSettings;
|
||||
|
||||
// Clone the options so we don't mutate the originals
|
||||
var merged = new PlatformEnvironmentSettingsOptions
|
||||
{
|
||||
ClientId = source.ClientId,
|
||||
AuthorizeEndpoint = source.AuthorizeEndpoint,
|
||||
TokenEndpoint = source.TokenEndpoint,
|
||||
LogoutEndpoint = source.LogoutEndpoint,
|
||||
RedirectUri = source.RedirectUri,
|
||||
PostLogoutRedirectUri = source.PostLogoutRedirectUri,
|
||||
Scope = source.Scope,
|
||||
Audience = source.Audience,
|
||||
DpopAlgorithms = new List<string>(source.DpopAlgorithms),
|
||||
RefreshLeewaySeconds = source.RefreshLeewaySeconds,
|
||||
ApiBaseUrls = new Dictionary<string, string>(source.ApiBaseUrls, StringComparer.OrdinalIgnoreCase),
|
||||
OtlpEndpoint = source.OtlpEndpoint,
|
||||
TelemetrySampleRate = source.TelemetrySampleRate,
|
||||
WelcomeTitle = source.WelcomeTitle,
|
||||
WelcomeMessage = source.WelcomeMessage,
|
||||
WelcomeDocsUrl = source.WelcomeDocsUrl,
|
||||
DoctorFixEnabled = source.DoctorFixEnabled,
|
||||
};
|
||||
|
||||
// Overlay DB values (Layer 3 — highest priority)
|
||||
var dbSettings = await _store.GetAllAsync(ct).ConfigureAwait(false);
|
||||
|
||||
foreach (var (key, value) in dbSettings)
|
||||
{
|
||||
if (key.StartsWith("ApiBaseUrls:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var serviceName = key["ApiBaseUrls:".Length..];
|
||||
merged.ApiBaseUrls[serviceName] = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Map scalar settings by key name
|
||||
ApplyScalarSetting(merged, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
private static void ApplyScalarSetting(PlatformEnvironmentSettingsOptions options, string key, string value)
|
||||
{
|
||||
// Case-insensitive key matching for known scalar settings
|
||||
if (string.Equals(key, "ClientId", StringComparison.OrdinalIgnoreCase))
|
||||
options.ClientId = value;
|
||||
else if (string.Equals(key, "AuthorizeEndpoint", StringComparison.OrdinalIgnoreCase))
|
||||
options.AuthorizeEndpoint = value;
|
||||
else if (string.Equals(key, "TokenEndpoint", StringComparison.OrdinalIgnoreCase))
|
||||
options.TokenEndpoint = value;
|
||||
else if (string.Equals(key, "LogoutEndpoint", StringComparison.OrdinalIgnoreCase))
|
||||
options.LogoutEndpoint = value;
|
||||
else if (string.Equals(key, "RedirectUri", StringComparison.OrdinalIgnoreCase))
|
||||
options.RedirectUri = value;
|
||||
else if (string.Equals(key, "PostLogoutRedirectUri", StringComparison.OrdinalIgnoreCase))
|
||||
options.PostLogoutRedirectUri = value;
|
||||
else if (string.Equals(key, "Scope", StringComparison.OrdinalIgnoreCase))
|
||||
options.Scope = value;
|
||||
else if (string.Equals(key, "Audience", StringComparison.OrdinalIgnoreCase))
|
||||
options.Audience = value;
|
||||
else if (string.Equals(key, "OtlpEndpoint", StringComparison.OrdinalIgnoreCase))
|
||||
options.OtlpEndpoint = value;
|
||||
else if (string.Equals(key, "TelemetrySampleRate", StringComparison.OrdinalIgnoreCase)
|
||||
&& double.TryParse(value, out var rate))
|
||||
options.TelemetrySampleRate = rate;
|
||||
else if (string.Equals(key, "WelcomeTitle", StringComparison.OrdinalIgnoreCase))
|
||||
options.WelcomeTitle = value;
|
||||
else if (string.Equals(key, "WelcomeMessage", StringComparison.OrdinalIgnoreCase))
|
||||
options.WelcomeMessage = value;
|
||||
else if (string.Equals(key, "WelcomeDocsUrl", StringComparison.OrdinalIgnoreCase))
|
||||
options.WelcomeDocsUrl = value;
|
||||
else if (string.Equals(key, "DoctorFixEnabled", StringComparison.OrdinalIgnoreCase)
|
||||
&& bool.TryParse(value, out var fix))
|
||||
options.DoctorFixEnabled = fix;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user