Introduce Vexer platform scaffolding and enrich Concelier merge

This commit is contained in:
master
2025-10-15 19:20:13 +03:00
parent aef9dec6f1
commit 6215a709e8
125 changed files with 9383 additions and 3306 deletions

View File

@@ -0,0 +1,128 @@
using System.Collections.Immutable;
using System.IO;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using StellaOps.Vexer.Core;
using StellaOps.Vexer.Policy;
using StellaOps.Vexer.Storage.Mongo;
namespace StellaOps.Vexer.Export;
public interface IExportEngine
{
ValueTask<VexExportManifest> ExportAsync(VexExportRequestContext context, CancellationToken cancellationToken);
}
public sealed record VexExportRequestContext(
VexQuery Query,
VexExportFormat Format,
DateTimeOffset RequestedAt,
bool ForceRefresh = false);
public interface IVexExportDataSource
{
ValueTask<VexExportDataSet> FetchAsync(VexQuery query, CancellationToken cancellationToken);
}
public sealed record VexExportDataSet(
ImmutableArray<VexConsensus> Consensus,
ImmutableArray<VexClaim> Claims,
ImmutableArray<string> SourceProviders);
public sealed class VexExportEngine : IExportEngine
{
private readonly IVexExportStore _exportStore;
private readonly IVexPolicyEvaluator _policyEvaluator;
private readonly IVexExportDataSource _dataSource;
private readonly IReadOnlyDictionary<VexExportFormat, IVexExporter> _exporters;
private readonly ILogger<VexExportEngine> _logger;
public VexExportEngine(
IVexExportStore exportStore,
IVexPolicyEvaluator policyEvaluator,
IVexExportDataSource dataSource,
IEnumerable<IVexExporter> exporters,
ILogger<VexExportEngine> logger)
{
_exportStore = exportStore ?? throw new ArgumentNullException(nameof(exportStore));
_policyEvaluator = policyEvaluator ?? throw new ArgumentNullException(nameof(policyEvaluator));
_dataSource = dataSource ?? throw new ArgumentNullException(nameof(dataSource));
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
if (exporters is null)
{
throw new ArgumentNullException(nameof(exporters));
}
_exporters = exporters.ToDictionary(x => x.Format);
}
public async ValueTask<VexExportManifest> ExportAsync(VexExportRequestContext context, CancellationToken cancellationToken)
{
ArgumentNullException.ThrowIfNull(context);
var signature = VexQuerySignature.FromQuery(context.Query);
if (!context.ForceRefresh)
{
var cached = await _exportStore.FindAsync(signature, context.Format, cancellationToken).ConfigureAwait(false);
if (cached is not null)
{
_logger.LogInformation("Reusing cached export for {Signature} ({Format})", signature.Value, context.Format);
return cached with { FromCache = true };
}
}
var dataset = await _dataSource.FetchAsync(context.Query, cancellationToken).ConfigureAwait(false);
var exporter = ResolveExporter(context.Format);
var exportRequest = new VexExportRequest(
context.Query,
dataset.Consensus,
dataset.Claims,
context.RequestedAt);
var digest = exporter.Digest(exportRequest);
await using var buffer = new MemoryStream();
var result = await exporter.SerializeAsync(exportRequest, buffer, cancellationToken).ConfigureAwait(false);
var exportId = FormattableString.Invariant($"exports/{context.RequestedAt:yyyyMMddTHHmmssfffZ}/{digest.Digest}");
var manifest = new VexExportManifest(
exportId,
signature,
context.Format,
context.RequestedAt,
digest,
dataset.Claims.Length,
dataset.SourceProviders,
fromCache: false,
consensusRevision: _policyEvaluator.Version,
attestation: null,
sizeBytes: result.BytesWritten);
await _exportStore.SaveAsync(manifest, cancellationToken).ConfigureAwait(false);
_logger.LogInformation(
"Export generated for {Signature} ({Format}) size={SizeBytes} bytes",
signature.Value,
context.Format,
result.BytesWritten);
return manifest;
}
private IVexExporter ResolveExporter(VexExportFormat format)
=> _exporters.TryGetValue(format, out var exporter)
? exporter
: throw new InvalidOperationException($"No exporter registered for format '{format}'.");
}
public static class VexExportServiceCollectionExtensions
{
public static IServiceCollection AddVexExportEngine(this IServiceCollection services)
{
services.AddSingleton<IExportEngine, VexExportEngine>();
return services;
}
}