Files
taxbaik/TaxBaik.Web/Services/TelegramAlertGate.cs
T
kjh2064 d780fecf8c
TaxBaik CI/CD / build-and-deploy (push) Successful in 4m30s
Harden admin telemetry and deployment safeguards
2026-07-02 16:10:15 +09:00

58 lines
1.7 KiB
C#

using System.Collections.Concurrent;
using System.Security.Cryptography;
using System.Text;
namespace TaxBaik.Web.Services;
internal static class TelegramAlertGate
{
private sealed record GateEntry(DateTimeOffset WindowStart, int Count);
private static readonly ConcurrentDictionary<string, GateEntry> Gates = new();
public static bool ShouldSend(string category, string content, TimeSpan window, int maxPerWindow = 1)
{
if (string.IsNullOrWhiteSpace(category))
return false;
var now = DateTimeOffset.UtcNow;
var key = $"{category}:{Fingerprint(content)}";
while (true)
{
if (!Gates.TryGetValue(key, out var current))
{
var initial = new GateEntry(now, 1);
if (Gates.TryAdd(key, initial))
return true;
continue;
}
if (now - current.WindowStart >= window)
{
var reset = new GateEntry(now, 1);
if (Gates.TryUpdate(key, reset, current))
return true;
continue;
}
if (current.Count >= maxPerWindow)
return false;
var incremented = current with { Count = current.Count + 1 };
if (Gates.TryUpdate(key, incremented, current))
return true;
}
}
private static string Fingerprint(string content)
{
if (string.IsNullOrEmpty(content))
return "empty";
var normalized = content.Length > 1500 ? content[..1500] : content;
var bytes = SHA256.HashData(Encoding.UTF8.GetBytes(normalized));
return Convert.ToHexString(bytes);
}
}