Files
vigilcare-clinical/VigilCareClinicalAPI/Services/Simulation/ScenarioCatalog.cs
T
voltsrage 24f45851e9
CI / frontend (push) Canceled after 0s
CI / backend (push) Canceled after 8m32s
feature: In-App Simulation Runner (Backend)
2026-08-06 01:52:53 +08:00

80 lines
2.5 KiB
C#

using VigilCare.Simulation;
public interface IScenarioCatalog
{
IReadOnlyList<ScenarioFile> ListScenarios();
ScenarioFile? GetById(string scenarioId);
}
public sealed class ScenarioCatalog : IScenarioCatalog
{
private readonly string _directory;
private readonly object _gate = new();
private IReadOnlyList<(ScenarioFile Scenario, string Path, DateTime LastWriteUtc)> _entries =
Array.Empty<(ScenarioFile, string, DateTime)>();
public ScenarioCatalog(Microsoft.Extensions.Options.IOptions<SimulationOptions> options)
{
_directory = options.Value.ScenarioDirectory;
}
public IReadOnlyList<ScenarioFile> ListScenarios()
{
RefreshIfNeeded();
return _entries.Select(e => e.Scenario).ToList();
}
public ScenarioFile? GetById(string scenarioId)
{
RefreshIfNeeded();
return _entries
.Select(e => e.Scenario)
.FirstOrDefault(s => string.Equals(
s.Scenario.Id, scenarioId, StringComparison.OrdinalIgnoreCase));
}
private void RefreshIfNeeded()
{
lock (_gate)
{
if (!Directory.Exists(_directory))
{
_entries = Array.Empty<(ScenarioFile, string, DateTime)>();
return;
}
var disk = Directory.EnumerateFiles(_directory, "*.json")
.Where(p => !string.Equals(
Path.GetFileName(p), "schema.json", StringComparison.OrdinalIgnoreCase))
.Select(p => (Path: p, LastWriteUtc: File.GetLastWriteTimeUtc(p)))
.OrderBy(x => x.Path, StringComparer.OrdinalIgnoreCase)
.ToList();
var unchanged = _entries.Count == disk.Count
&& _entries.Zip(disk, (cached, onDisk) =>
cached.Path == onDisk.Path && cached.LastWriteUtc == onDisk.LastWriteUtc)
.All(eq => eq);
if (unchanged)
return;
var loaded = new List<(ScenarioFile Scenario, string Path, DateTime LastWriteUtc)>();
foreach (var file in disk)
{
try
{
loaded.Add((ScenarioLoader.Load(file.Path), file.Path, file.LastWriteUtc));
}
catch
{
// Skip corrupt files — catalogue must stay resilient.
}
}
_entries = loaded
.OrderBy(e => e.Scenario.Scenario.Id, StringComparer.OrdinalIgnoreCase)
.ToList();
}
}
}