stabilizaiton work - projects rework for maintenanceability and ui livening
This commit is contained in:
15
src/__Libraries/StellaOps.Settings/StellaOps.Settings.csproj
Normal file
15
src/__Libraries/StellaOps.Settings/StellaOps.Settings.csproj
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
190
src/__Libraries/StellaOps.Settings/StellaOpsCorsSettings.cs
Normal file
190
src/__Libraries/StellaOps.Settings/StellaOpsCorsSettings.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
// Copyright (c) StellaOps. All rights reserved.
|
||||
// Licensed under BUSL-1.1. See LICENSE in the project root.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace StellaOps.Settings;
|
||||
|
||||
/// <summary>
|
||||
/// POCO that holds resolved CORS settings for Stella Ops web services.
|
||||
/// Supports a priority cascade: env vars → config keys → legacy env vars → legacy config keys → defaults.
|
||||
/// </summary>
|
||||
public sealed class StellaOpsCorsSettings
|
||||
{
|
||||
public bool Enabled { get; set; }
|
||||
public string[] Origins { get; set; } = [];
|
||||
|
||||
// ── Primary env vars ───────────────────────────────────────────────
|
||||
public const string EnvEnabled = "STELLAOPS_WEBSERVICES_CORS";
|
||||
public const string EnvOrigin = "STELLAOPS_WEBSERVICES_CORS_ORIGIN";
|
||||
|
||||
// ── Primary config keys (appsettings.json / YAML) ──────────────────
|
||||
public const string ConfigEnabled = "StellaOps:WebServices:Cors:Enabled";
|
||||
public const string ConfigOrigin = "StellaOps:WebServices:Cors:Origin";
|
||||
|
||||
// ── Legacy (fallback) ──────────────────────────────────────────────
|
||||
public const string LegacyEnvEnabled = "STELLAOPS_CORS_ENABLED";
|
||||
public const string LegacyEnvOrigin = "STELLAOPS_CORS_ALLOWED_ORIGIN";
|
||||
public const string LegacyConfigEnabled = "StellaOps:Cors:Enabled";
|
||||
public const string LegacyConfigOrigin = "StellaOps:Cors:AllowedOrigin";
|
||||
|
||||
/// <summary>
|
||||
/// Default origins used in Development when no explicit origin is configured.
|
||||
/// </summary>
|
||||
public static readonly string[] DefaultDevOrigins =
|
||||
[
|
||||
"https://stella-ops.local",
|
||||
"https://stella-ops.local:10000",
|
||||
"https://localhost:10000"
|
||||
];
|
||||
|
||||
/// <summary>
|
||||
/// Resolves CORS settings using a priority cascade:
|
||||
/// env vars → config keys → legacy env vars → legacy config keys → built-in defaults.
|
||||
/// </summary>
|
||||
public static StellaOpsCorsSettings Resolve(IConfiguration configuration, bool isDevelopment)
|
||||
{
|
||||
return Resolve(configuration, isDevelopment, defaultEnabled: null, defaultOrigins: null, onNotConfigured: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves CORS settings with explicit default values used when no configuration source
|
||||
/// provides a value (instead of the built-in defaults).
|
||||
/// </summary>
|
||||
/// <param name="configuration">Application configuration.</param>
|
||||
/// <param name="isDevelopment">Whether the host is running in the Development environment.</param>
|
||||
/// <param name="defaultEnabled">Default value for <see cref="Enabled"/> when no source provides a value.</param>
|
||||
/// <param name="defaultOrigins">Default value for <see cref="Origins"/> when no source provides a value.</param>
|
||||
public static StellaOpsCorsSettings Resolve(
|
||||
IConfiguration configuration,
|
||||
bool isDevelopment,
|
||||
bool defaultEnabled,
|
||||
string[] defaultOrigins)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(defaultOrigins);
|
||||
return Resolve(configuration, isDevelopment, (bool?)defaultEnabled, defaultOrigins, onNotConfigured: null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resolves CORS settings with a callback that is invoked when the full cascade
|
||||
/// finds no explicit configuration. The callback receives a settings object
|
||||
/// populated with built-in defaults and may inspect or replace it.
|
||||
/// </summary>
|
||||
/// <param name="configuration">Application configuration.</param>
|
||||
/// <param name="isDevelopment">Whether the host is running in the Development environment.</param>
|
||||
/// <param name="onNotConfigured">
|
||||
/// Called when neither env vars nor config keys provide a value.
|
||||
/// Receives the settings with built-in defaults applied; return value replaces them.
|
||||
/// </param>
|
||||
public static StellaOpsCorsSettings Resolve(
|
||||
IConfiguration configuration,
|
||||
bool isDevelopment,
|
||||
Func<StellaOpsCorsSettings, StellaOpsCorsSettings> onNotConfigured)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(onNotConfigured);
|
||||
return Resolve(configuration, isDevelopment, defaultEnabled: null, defaultOrigins: null, onNotConfigured);
|
||||
}
|
||||
|
||||
private static StellaOpsCorsSettings Resolve(
|
||||
IConfiguration configuration,
|
||||
bool isDevelopment,
|
||||
bool? defaultEnabled,
|
||||
string[]? defaultOrigins,
|
||||
Func<StellaOpsCorsSettings, StellaOpsCorsSettings>? onNotConfigured)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(configuration);
|
||||
|
||||
var (enabled, enabledFromCascade) = ResolveBool(
|
||||
configuration, isDevelopment,
|
||||
EnvEnabled, ConfigEnabled,
|
||||
LegacyEnvEnabled, LegacyConfigEnabled,
|
||||
defaultEnabled);
|
||||
|
||||
var (origins, originsFromCascade) = ResolveOrigins(
|
||||
configuration, isDevelopment,
|
||||
EnvOrigin, ConfigOrigin,
|
||||
LegacyEnvOrigin, LegacyConfigOrigin,
|
||||
defaultOrigins);
|
||||
|
||||
var settings = new StellaOpsCorsSettings { Enabled = enabled, Origins = origins };
|
||||
|
||||
// If neither field was resolved from the cascade and a callback is provided, invoke it.
|
||||
if (!enabledFromCascade && !originsFromCascade && onNotConfigured is not null)
|
||||
{
|
||||
settings = onNotConfigured(settings);
|
||||
}
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
/// <returns>A tuple of (resolved value, whether a cascade source provided the value).</returns>
|
||||
private static (bool Value, bool FromCascade) ResolveBool(
|
||||
IConfiguration configuration,
|
||||
bool isDevelopment,
|
||||
string envKey, string configKey,
|
||||
string legacyEnvKey, string legacyConfigKey,
|
||||
bool? explicitDefault)
|
||||
{
|
||||
// 1. Primary env var
|
||||
var value = Environment.GetEnvironmentVariable(envKey);
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
return (IsTruthy(value), true);
|
||||
|
||||
// 2. Primary config key
|
||||
var configValue = configuration[configKey];
|
||||
if (!string.IsNullOrWhiteSpace(configValue))
|
||||
return (IsTruthy(configValue), true);
|
||||
|
||||
// 3. Legacy env var
|
||||
value = Environment.GetEnvironmentVariable(legacyEnvKey);
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
return (IsTruthy(value), true);
|
||||
|
||||
// 4. Legacy config key
|
||||
configValue = configuration[legacyConfigKey];
|
||||
if (!string.IsNullOrWhiteSpace(configValue))
|
||||
return (IsTruthy(configValue), true);
|
||||
|
||||
// 5. Explicit default or built-in default
|
||||
return (explicitDefault ?? isDevelopment, false);
|
||||
}
|
||||
|
||||
/// <returns>A tuple of (resolved origins, whether a cascade source provided the value).</returns>
|
||||
private static (string[] Value, bool FromCascade) ResolveOrigins(
|
||||
IConfiguration configuration,
|
||||
bool isDevelopment,
|
||||
string envKey, string configKey,
|
||||
string legacyEnvKey, string legacyConfigKey,
|
||||
string[]? explicitDefault)
|
||||
{
|
||||
// 1. Primary env var
|
||||
var value = Environment.GetEnvironmentVariable(envKey);
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
return (SplitOrigins(value), true);
|
||||
|
||||
// 2. Primary config key
|
||||
var configValue = configuration[configKey];
|
||||
if (!string.IsNullOrWhiteSpace(configValue))
|
||||
return (SplitOrigins(configValue), true);
|
||||
|
||||
// 3. Legacy env var
|
||||
value = Environment.GetEnvironmentVariable(legacyEnvKey);
|
||||
if (!string.IsNullOrWhiteSpace(value))
|
||||
return (SplitOrigins(value), true);
|
||||
|
||||
// 4. Legacy config key
|
||||
configValue = configuration[legacyConfigKey];
|
||||
if (!string.IsNullOrWhiteSpace(configValue))
|
||||
return (SplitOrigins(configValue), true);
|
||||
|
||||
// 5. Explicit default or built-in default
|
||||
return (explicitDefault ?? (isDevelopment ? DefaultDevOrigins : []), false);
|
||||
}
|
||||
|
||||
private static bool IsTruthy(string value) =>
|
||||
string.Equals(value, "true", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(value, "1", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static string[] SplitOrigins(string raw) =>
|
||||
raw.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||
}
|
||||
Reference in New Issue
Block a user