feat: add service import shadowing detection (Gap 9.10)
Implements ServiceImportShadowed, GetShadowedServiceImports, HasShadowedImports, and CheckServiceImportShadowing on Account to detect when local SubList subscriptions would intercept messages before a service import can receive them. Adds ShadowCheckResult record and 10 tests covering exact, wildcard, and gt-wildcard shadowing scenarios.
This commit is contained in:
@@ -777,9 +777,89 @@ public sealed class Account : IDisposable
|
||||
/// <summary>Returns a snapshot of all reply subjects currently in the reverse response map.</summary>
|
||||
public IReadOnlyList<string> GetReverseResponseMapKeys() => [.. _reverseResponseMap.Keys];
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether any local subscription in this account's SubList would shadow
|
||||
/// (intercept) messages on the given service import subject, preventing the import
|
||||
/// from receiving them.
|
||||
/// Go reference: accounts.go serviceImportShadowed (~line 2015).
|
||||
/// </summary>
|
||||
public bool ServiceImportShadowed(string importSubject)
|
||||
{
|
||||
var matchResult = SubList.Match(importSubject);
|
||||
return matchResult.PlainSubs.Length > 0 || matchResult.QueueSubs.Length > 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns all service import subjects registered on this account that are currently
|
||||
/// shadowed by a local subscription in the SubList.
|
||||
/// Go reference: accounts.go serviceImportShadowed (~line 2015).
|
||||
/// </summary>
|
||||
public IReadOnlyList<string> GetShadowedServiceImports()
|
||||
{
|
||||
var shadowed = new List<string>();
|
||||
foreach (var subject in Imports.Services.Keys)
|
||||
{
|
||||
if (ServiceImportShadowed(subject))
|
||||
shadowed.Add(subject);
|
||||
}
|
||||
return shadowed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns <see langword="true"/> when at least one registered service import subject
|
||||
/// is shadowed by a local subscription.
|
||||
/// Go reference: accounts.go serviceImportShadowed (~line 2015).
|
||||
/// </summary>
|
||||
public bool HasShadowedImports
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var subject in Imports.Services.Keys)
|
||||
{
|
||||
if (ServiceImportShadowed(subject))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a detailed <see cref="ShadowCheckResult"/> for the given import subject,
|
||||
/// including the list of local subscription subjects that shadow it.
|
||||
/// Go reference: accounts.go serviceImportShadowed (~line 2015).
|
||||
/// </summary>
|
||||
public ShadowCheckResult CheckServiceImportShadowing(string importSubject)
|
||||
{
|
||||
var matchResult = SubList.Match(importSubject);
|
||||
var shadowingSubs = new List<string>();
|
||||
|
||||
foreach (var sub in matchResult.PlainSubs)
|
||||
shadowingSubs.Add(sub.Subject);
|
||||
|
||||
foreach (var queueGroup in matchResult.QueueSubs)
|
||||
foreach (var sub in queueGroup)
|
||||
shadowingSubs.Add(sub.Subject);
|
||||
|
||||
bool isShadowed = shadowingSubs.Count > 0;
|
||||
return new ShadowCheckResult(isShadowed, importSubject, shadowingSubs);
|
||||
}
|
||||
|
||||
public void Dispose() => SubList.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Result of <see cref="Account.CheckServiceImportShadowing"/> describing whether a service import
|
||||
/// subject is intercepted by a local subscription and which subscriptions are responsible.
|
||||
/// Go reference: accounts.go serviceImportShadowed (~line 2015).
|
||||
/// </summary>
|
||||
/// <param name="IsShadowed">Whether any local subscription shadows the import subject.</param>
|
||||
/// <param name="ImportSubject">The service import subject that was checked.</param>
|
||||
/// <param name="ShadowingSubscriptions">The subjects of local subscriptions that match the import subject.</param>
|
||||
public sealed record ShadowCheckResult(
|
||||
bool IsShadowed,
|
||||
string ImportSubject,
|
||||
IReadOnlyList<string> ShadowingSubscriptions);
|
||||
|
||||
/// <summary>
|
||||
/// Carries the result of a <see cref="Account.CheckServiceResponse"/> call.
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user