using System.Collections.Concurrent; using Microsoft.Extensions.Options; using ZymonicGateway.Contracts; using ZymonicGateway.Options; namespace ZymonicGateway.Services; public sealed class ZymonicGatewayDebugRequestDecider : IZymonicGatewayDebugRequestDecider { private readonly IOptionsMonitor _options; private readonly ConcurrentDictionary _runtimeRules = new(StringComparer.OrdinalIgnoreCase); public ZymonicGatewayDebugRequestDecider(IOptionsMonitor options) { _options = options; } public bool ShouldDebug(ZymonicGatewayQueuedWork request) { var matchedRule = GetRules().LastOrDefault(rule => Matches(rule, request)); return matchedRule?.Enabled ?? false; } public IReadOnlyList GetRules() { return _options.CurrentValue.Debug.Rules .Concat(_runtimeRules.Values) .ToList(); } public ZymonicGatewayDebugRule UpsertRuntimeRule(string name, ZymonicGatewayDebugRule rule) { rule.Name = name; _runtimeRules[name] = rule; return rule; } public bool RemoveRuntimeRule(string name) { return _runtimeRules.TryRemove(name, out _); } public void ClearRuntimeRules() { _runtimeRules.Clear(); } private static bool Matches(ZymonicGatewayDebugRule rule, ZymonicGatewayQueuedWork request) { return Matches(rule.RequestId, request.RequestId) && Matches(rule.Source, request.Source) && Matches(rule.Route, request.Route) && Matches(rule.EffectiveUser, request.EffectiveUser) && Matches(rule.AuthMethod, request.AuthMethod); } private static bool Matches(Guid? expected, Guid actual) { return expected is null || expected == actual; } private static bool Matches(string? expected, string? actual) { return string.IsNullOrWhiteSpace(expected) || string.Equals(expected, actual, StringComparison.OrdinalIgnoreCase); } }