feature: In-App Simulation Runner (Backend)
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 8m32s

This commit is contained in:
voltsrage
2026-08-06 01:52:53 +08:00
parent 943d41339c
commit 24f45851e9
83 changed files with 3974 additions and 120 deletions
@@ -0,0 +1,59 @@
using System.Text.Json;
namespace VigilCare.Simulation;
public static class ScenarioLoader
{
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true
};
public static ScenarioFile Load(string path)
{
if (!File.Exists(path))
throw new FileNotFoundException($"Scenario file not found: {path}");
var json = File.ReadAllText(path);
var scenario = JsonSerializer.Deserialize<ScenarioFile>(json, JsonOptions)
?? throw new InvalidOperationException($"Failed to deserialize: {path}");
return scenario with
{
Events = scenario.Events.OrderBy(e => e.OffsetMinutes).ToList()
};
}
/// <summary>
/// Enumerates <c>*.json</c> in <paramref name="directory"/>, skips files that
/// fail to deserialize, and returns pairs sorted by <see cref="ScenarioMeta.Id"/>.
/// </summary>
public static IReadOnlyList<(ScenarioFile Scenario, string Path)> LoadAll(string directory)
{
if (!Directory.Exists(directory))
return Array.Empty<(ScenarioFile, string)>();
var results = new List<(ScenarioFile Scenario, string Path)>();
foreach (var path in Directory.EnumerateFiles(directory, "*.json")
.Where(p => !string.Equals(
Path.GetFileName(p), "schema.json", StringComparison.OrdinalIgnoreCase))
.OrderBy(p => p, StringComparer.OrdinalIgnoreCase))
{
try
{
results.Add((Load(path), path));
}
catch
{
// Skip files that fail to deserialize — catalogue must stay resilient.
}
}
return results
.OrderBy(r => r.Scenario.Scenario.Id, StringComparer.OrdinalIgnoreCase)
.ToList();
}
}