mirror of
https://github.com/permissionlesstech/bitchat-android.git
synced 2026-08-15 06:56:30 +00:00
Opening the About sheet runs a release check, and an exhausted quota fed itself: only successes were cached, and a 403 reporting zero remaining was classed retryable, so every sheet open spent three more requests rediscovering the same limit. Unauthenticated GitHub allows 60 requests an hour per IP, and over Tor that IP is an exit node shared with every other user on it, so the ceiling arrives far sooner than per-user maths suggests. Three changes: - Conditional requests. The client now stores the release ETag and replays it as If-None-Match. GitHub does not charge a 304 against the rate limit, so revalidating an expired cache is free where an unconditional refetch costs one of the 60. This is why neither polling nor long polling is the right answer here. - A rate-limit gate. X-RateLimit-Reset and Retry-After were read only to interpolate into an error string; they now set a deadline before which no request is sent at all. While blocked, a stale cached release is served in preference to an error the user cannot act on. Clamped to an hour so a bad header cannot lock the feature out, and a reset time in the past falls back to a fixed backoff rather than unblocking a skewed clock immediately. - Rate limits are no longer retried in-loop. The gate decides when it is worth asking again. A plain 403 is a permissions failure and is no longer retried either. The gate's decision logic is pure and unit tested. The wiring around it is not: that needs a MockWebServer, which is not currently a dependency. Known gap: the cache and ETag are in memory only, so a process restart still costs one request. Persisting them needs a Context threaded into what is currently a context-free object; left as a follow-up. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>