diff --git a/src/ScadaLink.Commons/Interfaces/Transport/IAuditCorrelationContext.cs b/src/ScadaLink.Commons/Interfaces/Transport/IAuditCorrelationContext.cs new file mode 100644 index 0000000..f042822 --- /dev/null +++ b/src/ScadaLink.Commons/Interfaces/Transport/IAuditCorrelationContext.cs @@ -0,0 +1,11 @@ +namespace ScadaLink.Commons.Interfaces.Transport; + +/// +/// Scoped service the bundle importer sets to thread a BundleImportId through to +/// the audit log entries emitted by the audited repository methods invoked during +/// ApplyAsync. AuditService reads this and stamps every AuditLogEntry it writes. +/// +public interface IAuditCorrelationContext +{ + Guid? BundleImportId { get; set; } +} diff --git a/src/ScadaLink.Commons/Interfaces/Transport/IBundleExporter.cs b/src/ScadaLink.Commons/Interfaces/Transport/IBundleExporter.cs new file mode 100644 index 0000000..e5b0684 --- /dev/null +++ b/src/ScadaLink.Commons/Interfaces/Transport/IBundleExporter.cs @@ -0,0 +1,13 @@ +using ScadaLink.Commons.Types.Transport; + +namespace ScadaLink.Commons.Interfaces.Transport; + +public interface IBundleExporter +{ + Task ExportAsync( + ExportSelection selection, + string user, + string sourceEnvironment, + string? passphrase, + CancellationToken cancellationToken = default); +} diff --git a/src/ScadaLink.Commons/Interfaces/Transport/IBundleImporter.cs b/src/ScadaLink.Commons/Interfaces/Transport/IBundleImporter.cs new file mode 100644 index 0000000..d259d39 --- /dev/null +++ b/src/ScadaLink.Commons/Interfaces/Transport/IBundleImporter.cs @@ -0,0 +1,14 @@ +using ScadaLink.Commons.Types.Transport; + +namespace ScadaLink.Commons.Interfaces.Transport; + +public interface IBundleImporter +{ + Task LoadAsync(Stream bundleStream, string? passphrase, CancellationToken ct = default); + Task PreviewAsync(Guid sessionId, CancellationToken ct = default); + Task ApplyAsync( + Guid sessionId, + IReadOnlyList resolutions, + string user, + CancellationToken ct = default); +} diff --git a/src/ScadaLink.Commons/Interfaces/Transport/IBundleSessionStore.cs b/src/ScadaLink.Commons/Interfaces/Transport/IBundleSessionStore.cs new file mode 100644 index 0000000..0f8a178 --- /dev/null +++ b/src/ScadaLink.Commons/Interfaces/Transport/IBundleSessionStore.cs @@ -0,0 +1,11 @@ +using ScadaLink.Commons.Types.Transport; + +namespace ScadaLink.Commons.Interfaces.Transport; + +public interface IBundleSessionStore +{ + BundleSession Open(BundleSession session); + BundleSession? Get(Guid sessionId); + void Remove(Guid sessionId); + void EvictExpired(); +} diff --git a/src/ScadaLink.Commons/Types/Transport/BundleSession.cs b/src/ScadaLink.Commons/Types/Transport/BundleSession.cs new file mode 100644 index 0000000..b495c0e --- /dev/null +++ b/src/ScadaLink.Commons/Types/Transport/BundleSession.cs @@ -0,0 +1,11 @@ +namespace ScadaLink.Commons.Types.Transport; + +public sealed class BundleSession +{ + public Guid SessionId { get; init; } + public BundleManifest Manifest { get; init; } = null!; + public byte[] DecryptedContent { get; init; } = Array.Empty(); + public DateTimeOffset ExpiresAt { get; init; } + public int FailedUnlockAttempts { get; set; } + public bool Locked => FailedUnlockAttempts >= 3; +} diff --git a/src/ScadaLink.Commons/Types/Transport/ExportSelection.cs b/src/ScadaLink.Commons/Types/Transport/ExportSelection.cs new file mode 100644 index 0000000..0c7ce1b --- /dev/null +++ b/src/ScadaLink.Commons/Types/Transport/ExportSelection.cs @@ -0,0 +1,12 @@ +namespace ScadaLink.Commons.Types.Transport; + +public sealed record ExportSelection( + IReadOnlyList TemplateIds, + IReadOnlyList SharedScriptIds, + IReadOnlyList ExternalSystemIds, + IReadOnlyList DatabaseConnectionIds, + IReadOnlyList NotificationListIds, + IReadOnlyList SmtpConfigurationIds, + IReadOnlyList ApiKeyIds, + IReadOnlyList ApiMethodIds, + bool IncludeDependencies); diff --git a/src/ScadaLink.Commons/Types/Transport/ImportPreview.cs b/src/ScadaLink.Commons/Types/Transport/ImportPreview.cs new file mode 100644 index 0000000..1ee54b6 --- /dev/null +++ b/src/ScadaLink.Commons/Types/Transport/ImportPreview.cs @@ -0,0 +1,16 @@ +namespace ScadaLink.Commons.Types.Transport; + +public enum ConflictKind { Identical, Modified, New, Blocker } + +public sealed record ImportPreviewItem( + string EntityType, + string Name, + int? ExistingVersion, + int? IncomingVersion, + ConflictKind Kind, + string? FieldDiffJson, + string? BlockerReason); + +public sealed record ImportPreview( + Guid SessionId, + IReadOnlyList Items); diff --git a/src/ScadaLink.Commons/Types/Transport/ImportResolution.cs b/src/ScadaLink.Commons/Types/Transport/ImportResolution.cs new file mode 100644 index 0000000..5d3958c --- /dev/null +++ b/src/ScadaLink.Commons/Types/Transport/ImportResolution.cs @@ -0,0 +1,9 @@ +namespace ScadaLink.Commons.Types.Transport; + +public enum ResolutionAction { Add, Overwrite, Skip, Rename } + +public sealed record ImportResolution( + string EntityType, + string Name, + ResolutionAction Action, + string? RenameTo); diff --git a/src/ScadaLink.Commons/Types/Transport/ImportResult.cs b/src/ScadaLink.Commons/Types/Transport/ImportResult.cs new file mode 100644 index 0000000..34db172 --- /dev/null +++ b/src/ScadaLink.Commons/Types/Transport/ImportResult.cs @@ -0,0 +1,10 @@ +namespace ScadaLink.Commons.Types.Transport; + +public sealed record ImportResult( + Guid BundleImportId, + int Added, + int Overwritten, + int Skipped, + int Renamed, + IReadOnlyList StaleInstanceIds, + string AuditEventCorrelation);