using System.Text.Json; using System.Text.Json.Serialization; namespace WxAgent.Core; public sealed record RemoteConfigurationAuditEntry { [JsonPropertyName("at")] public DateTimeOffset At { get; init; } [JsonPropertyName("action")] public string Action { get; init; } = ""; [JsonPropertyName("configVersion")] public long ConfigVersion { get; init; } } public sealed record RemoteNodeConfiguration { [JsonPropertyName("remote")] public RemoteAgentOptions Remote { get; init; } = new(); [JsonPropertyName("reporting")] public ReportingConfig Reporting { get; init; } = new(); [JsonPropertyName("audit")] public IReadOnlyList Audit { get; init; } = []; public RemoteNodeConfiguration NormalizeAndValidate() { var reporting = (Reporting ?? new ReportingConfig()).NormalizeAndValidate(); if (Remote is { IsConfigured: true }) Remote.Validate(); return this with { Remote = Remote ?? new RemoteAgentOptions(), Reporting = reporting, Audit = (Audit ?? []).TakeLast(1000).ToArray() }; } } public static class RemoteNodeConfigurationStore { public static async Task LoadAsync(string path, CancellationToken cancellationToken = default) { try { await using var stream = File.OpenRead(path); var configuration = await JsonSerializer.DeserializeAsync(stream, RemoteJson.Options, cancellationToken); return (configuration ?? new RemoteNodeConfiguration()).NormalizeAndValidate(); } catch (FileNotFoundException) { return new RemoteNodeConfiguration(); } catch (DirectoryNotFoundException) { return new RemoteNodeConfiguration(); } catch (JsonException exception) { throw new WxAgentException(WxAgentErrorCode.InvalidArgument, "Remote node configuration is invalid JSON.", exception); } catch (WxAgentException) { throw; } } }