using System; using System.Collections.Concurrent; using System.Collections.Generic; namespace SNote.Server.Security; public class PeerCache { private readonly ConcurrentDictionary _downstreamPeers = new(StringComparer.OrdinalIgnoreCase); private readonly ConcurrentDictionary _recentBroadcastIds = new(StringComparer.OrdinalIgnoreCase); public void RegisterPeer(string peerUrl) { if (string.IsNullOrWhiteSpace(peerUrl)) return; var cleanUrl = peerUrl.Trim().TrimEnd('/'); _downstreamPeers.TryAdd(cleanUrl, 0); Console.WriteLine($"[PeerCache] Registered downstream peer node: {cleanUrl}"); } public void RemovePeer(string peerUrl) { if (string.IsNullOrWhiteSpace(peerUrl)) return; var cleanUrl = peerUrl.Trim().TrimEnd('/'); if (_downstreamPeers.TryRemove(cleanUrl, out _)) { Console.WriteLine($"[PeerCache] Evicted offline peer node: {cleanUrl}"); } } public List GetPeers() { return new List(_downstreamPeers.Keys); } public bool TryProcessBroadcast(string broadcastId) { if (string.IsNullOrWhiteSpace(broadcastId)) return false; // Clean up old entries to prevent infinite memory growth (older than 10 minutes) var cutoff = DateTime.UtcNow.AddMinutes(-10); foreach (var kvp in _recentBroadcastIds) { if (kvp.Value < cutoff) { _recentBroadcastIds.TryRemove(kvp.Key, out _); } } return _recentBroadcastIds.TryAdd(broadcastId, DateTime.UtcNow); } }