namespace BlueLaminate.Scraper.CsFloat; /// /// Rate-limit state parsed from a CSFloat API response's headers. The official /// docs don't pin down the exact header names, so this is populated generically /// (any header whose name contains "ratelimit"/"rate-limit", plus "retry-after") /// and keeps the map so the real names surface during the /// spike. A future catalog sweep uses / /// to pace requests and avoid 429s. /// /// Max requests allowed in the current window, if reported. /// Requests left in the current window, if reported. /// Raw reset value as sent (epoch seconds or seconds-until — unverified). /// Seconds to wait, from a Retry-After header (typically on 429). /// Every rate-limit-related header, verbatim, for inspection. public sealed record CsFloatRateLimit( int? Limit, int? Remaining, string? Reset, int? RetryAfter, IReadOnlyDictionary Raw) { public static readonly CsFloatRateLimit None = new(null, null, null, null, new Dictionary()); /// True when the API reports zero requests remaining. public bool IsExhausted => Remaining is <= 0; public override string ToString() => Raw.Count == 0 ? "rate-limit: (no headers)" : "rate-limit: " + string.Join(", ", Raw.Select(kv => $"{kv.Key}={kv.Value}")); }