Files
plezy/lib/services/trackers/tracker_constants.dart
edde746 6ab46ced54 fix(relay): claim OAuth callbacks before the code exchange and bound poster and poll traffic per IP
Two callbacks with the same state could both exchange the authorization code upstream (concurrently or by replay); the session is now atomically claimed under the proxy lock before the exchange.

GET /posters/ and the /auth/result long-poll had no per-IP limiting or concurrency bound, and every poster lookup serialized through an exclusive store lock; both endpoints now use the established limiter and non-expired hits take a read lock. The limiter also tracks active transfers per IP with caps below the global limits (4 for fetches, 2 for uploads), because one unauthenticated client could otherwise take all 16 global poster-fetch slots and hold them through slow ServeContent reads, starving everyone else with 429s; concurrency checks precede bucket charges so a capped denial consumes no admission tokens.

/auth/result gets its own per-IP budget instead of sharing /auth/start's burst-3 bucket, where two concurrent NAT'd sign-ins 429'd on the fourth request. It is charged only after the poll secret validates (bogus requests keep the generic 410 and cost nothing), denials carry an honest Retry-After, and the Dart poller - which treated 429 as terminal and abandoned a valid session - retries them until the session's 10-minute lifetime expires.
2026-08-21 19:23:43 +02:00

31 lines
1.5 KiB
Dart

/// Shared constants for tracker integrations.
class TrackerConstants {
TrackerConstants._();
/// Fallback watched threshold (percent) used only until the active server's
/// threshold is known. The operative value follows
/// [MediaServerClient.watchedThreshold] (captured per playback in
/// [TrackerCoordinator]); this constant just seeds the field before playback.
static const double watchedThresholdPercent = 80.0;
static const Duration requestTimeout = Duration(seconds: 20);
static const Duration authRequestTimeout = Duration(seconds: 15);
static const Duration refreshTimeout = Duration(seconds: 15);
static const Duration revokeTimeout = Duration(seconds: 10);
static const Duration oauthProxyPollTimeout = Duration(seconds: 65);
static const Duration oauthProxyRetryDelay = Duration(seconds: 2);
/// Mirrors the relay's server-side OAuth session TTL. Rate-limited (429)
/// polls are retried until this deadline; past it the session can no longer
/// succeed, so the poller surfaces the failure instead.
static const Duration oauthProxySessionTimeout = Duration(minutes: 10);
}
/// Identifier used across the app to disambiguate per-service operations.
/// The enum's `.name` forms part of the persistence key — do not rename
/// without a migration.
enum TrackerService { mal, anilist, simkl, trakt, mdblist }
/// Blacklist+[] syncs every library (the default); whitelist+[] syncs nothing.
enum TrackerLibraryFilterMode { blacklist, whitelist }