using System; using System.Collections.Generic; namespace Kerobot.Modules.AutoScriptResponder { /// /// Helper class for managing rate limit data. /// class RateLimit { public const ushort DefaultTimeout = 20; // Skeeter's a cool guy and you can't convince me otherwise. public ushort Timeout { get; } private readonly object _lock = new object(); private Dictionary _table = new Dictionary(); public RateLimit() : this(DefaultTimeout) { } public RateLimit(ushort timeout) => Timeout = timeout; /// /// 'Permit?' - Checks if the given value is permitted through the rate limit. /// Executing this method may create a rate limit entry for the given value. /// /// /// True if the given value is permitted by the rate limiter. public bool Permit(T value) { if (Timeout == 0) return true; lock (_lock) { Clean(); if (_table.ContainsKey(value)) return false; _table.Add(value, DateTime.Now); } return true; } /// /// Clean up expired entries. /// private void Clean() { var now = DateTime.Now; var newTable = new Dictionary(); foreach (var item in _table) { // Copy items that have not yet timed out to the new dictionary. Discard the rest. if (item.Value.AddSeconds(Timeout) > now) newTable.Add(item.Key, item.Value); } lock (_lock) _table = newTable; } } }