Files
fanuzu/app/lib/core/data/server_clock.dart

41 lines
1.5 KiB
Dart

import 'backend.dart';
/// 서버 시각 — 단말 시계와 서버 시계의 차이를 한 번 재어 앱 전체가 같이 쓴다.
///
/// 타임어택 창(`quests.activeFrom`~`activeTo`)은 서버 시각이다. 단말 시계로 세면 시계를
/// 돌린 단말에서 마감이 늘어나 보인다. 판정은 서버가 다시 하므로 이것은 표시용이다.
class ServerClock {
ServerClock._();
/// 서버 − 단말. 재지 못했으면 0 이다(단말 시계 그대로).
static Duration offset = Duration.zero;
static Future<void>? _synced;
static DateTime now() => DateTime.now().add(offset);
/// 세션당 한 번 `fnServerTime` 을 부른다. 실패하면 단말 시계로 두고 넘어간다.
static Future<void> ensure(Backend backend) => _synced ??= _sync(backend);
static Future<void> _sync(Backend backend) async {
try {
final sent = DateTime.now();
final reply = await backend.call('fnServerTime');
final received = DateTime.now();
final server = reply['now'];
if (server is! num) return;
// 왕복의 가운데를 서버가 답한 시각으로 본다.
final middle = sent.add(received.difference(sent) ~/ 2);
offset = DateTime.fromMillisecondsSinceEpoch(server.round()).difference(middle);
} catch (_) {
_synced = null; // 다음 기회에 다시 잰다.
}
}
/// 테스트가 회차마다 처음 상태로 돌린다.
static void reset() {
offset = Duration.zero;
_synced = null;
}
}