41 lines
1.5 KiB
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;
|
|
}
|
|
}
|