51 lines
1.5 KiB
C#
51 lines
1.5 KiB
C#
|
|
using Microsoft.Extensions.Hosting;
|
|
using System.Text;
|
|
using System.Text.Json;
|
|
|
|
namespace StellaOps.Policy.Engine.Overlay;
|
|
|
|
/// <summary>
|
|
/// Persists overlay projections as NDJSON files under overlay/{tenant}/{ruleId}/{version}.ndjson.
|
|
/// </summary>
|
|
internal sealed class FileOverlayStore : IOverlayStore
|
|
{
|
|
private readonly string _root;
|
|
|
|
public FileOverlayStore(IHostEnvironment env)
|
|
{
|
|
_root = Path.Combine(env.ContentRootPath, "overlay");
|
|
}
|
|
|
|
public async Task SaveAsync(OverlayProjection projection, CancellationToken cancellationToken = default)
|
|
{
|
|
if (projection is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(projection));
|
|
}
|
|
|
|
var tenant = Sanitize(projection.Tenant);
|
|
var rule = Sanitize(projection.RuleId);
|
|
var dir = Path.Combine(_root, tenant, rule);
|
|
Directory.CreateDirectory(dir);
|
|
|
|
var path = Path.Combine(dir, $"{projection.Version}.ndjson");
|
|
var lines = new[]
|
|
{
|
|
JsonSerializer.Serialize(new OverlayProjectionHeader("overlay-projection-v1")),
|
|
JsonSerializer.Serialize(projection)
|
|
};
|
|
await File.WriteAllLinesAsync(path, lines, Encoding.UTF8, cancellationToken).ConfigureAwait(false);
|
|
}
|
|
|
|
private static string Sanitize(string value)
|
|
{
|
|
foreach (var ch in Path.GetInvalidFileNameChars())
|
|
{
|
|
value = value.Replace(ch, '_');
|
|
}
|
|
|
|
return string.IsNullOrWhiteSpace(value) ? "unknown" : value;
|
|
}
|
|
}
|