Files
plezy/lib/services/trackers/device_code_poller.dart

45 lines
1.5 KiB
Dart

import 'dart:async';
import '../../models/trackers/device_code.dart';
/// Runs the RFC 8628 poll loop. Service-specific HTTP is delegated to [probe];
/// this helper owns interval decay (`slow_down`), the deadline window, and the
/// cancel-check cadence so Trakt and Simkl can share it.
///
/// [probe] must perform one poll attempt and return a single event.
/// [DevicePollSlowDown] triggers a 5-second interval bump; terminal events
/// ([DevicePollSuccess], [DevicePollDenied], [DevicePollExpired]) end the
/// stream.
Stream<DevicePollEvent> pollDeviceCode(
DeviceCode code, {
required Future<DevicePollEvent> Function() probe,
bool Function()? shouldCancel,
Future<void>? onCancel,
}) async* {
var interval = Duration(seconds: code.interval);
final deadline = DateTime.now().add(Duration(seconds: code.expiresIn));
while (DateTime.now().isBefore(deadline)) {
if (shouldCancel != null && shouldCancel()) return;
if (onCancel != null) {
await Future.any<void>([Future<void>.delayed(interval), onCancel]);
} else {
await Future<void>.delayed(interval);
}
if (shouldCancel != null && shouldCancel()) return;
final event = await probe();
yield event;
switch (event) {
case DevicePollSuccess() || DevicePollDenied() || DevicePollExpired():
return;
case DevicePollSlowDown():
interval += const Duration(seconds: 5);
case DevicePollPending():
break;
}
}
yield const DevicePollExpired();
}