feat(ui): explicit offline state inside an online game (+ offline word check)
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Failing after 12s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Failing after 1s
CI / deploy (pull_request) Has been skipped
CI / changes (pull_request) Successful in 3s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Failing after 12s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Failing after 1s
CI / deploy (pull_request) Has been skipped
When an online game loses the connection the game screen now says so and freezes instead of silently greying out: a "connection lost" banner appears and the rack, the move controls, the add-friend/block controls and the chat/dictionary entry all disable (a started move stays a draft, committed by the player on reconnect). It is driven off the net-state machine (netState.offline), so it also covers the Telegram/VK mini-apps, where a lost connection was previously mute in-game. If the player is already in the dictionary when the drop happens, the word check falls back to the game's pinned on-device dictionary (exact when that dawg is cached; "unavailable offline" otherwise) and the network-only complaint + external look-up hide. Chat, when already open, keeps its existing read-only degrade (send/nudge disable). New pure helper localWordCheck is unit-tested; the in-game gating gets an e2e.
This commit is contained in:
+11
-4
@@ -118,10 +118,17 @@ dropped). Horizontal scaling is explicit future work.
|
||||
one whose response was lost — its button is disabled while offline and re-issued on reconnect). A
|
||||
reachability watcher (a lightweight `profile.get` probe; a session-less native guest reconciles a
|
||||
server guest instead — that reconcile IS the probe) drives recovery, and the live `Subscribe` stream's
|
||||
drop/recovery feeds the same machine. **Telegram/VK are exempt** — always online: they are never fed an
|
||||
offline signal, and `offlineMode.active` is additionally hard-gated on `offlineCapable()` (false in
|
||||
those mini-apps), so nothing — not even a version lock — puts them in offline mode: no blue chrome, no
|
||||
local lobby, no transport kill switch and no device-local create paths.
|
||||
drop/recovery feeds the same machine. **Telegram/VK are exempt from the offline-*play* model** —
|
||||
`offlineMode.active` is hard-gated on `offlineCapable()` (false in those mini-apps), so nothing — not
|
||||
even a version lock — puts them in offline mode: no blue chrome, no local lobby, no transport kill
|
||||
switch and no device-local create paths. The machine still tracks reachability there, though: a
|
||||
connection lost **inside an online game** is surfaced on **every platform**, driven off the machine's
|
||||
confirmed-offline state (`netState.offline`, not `offlineMode.active`) — the game screen shows a
|
||||
*connection lost* banner and **freezes** the tray, the move controls, the add-friend/block controls and
|
||||
the chat/dictionary entry (a started move stays a draft, re-committed by the player on reconnect), and
|
||||
the word-check tool falls back to the game's pinned on-device dictionary (`ui/src/lib/dict/check.ts`,
|
||||
exact when that dawg is cached, else *unavailable*) with its network-only complaint and external
|
||||
look-up hidden.
|
||||
**Edge hardening:** every request body on the public listener is capped at
|
||||
`GATEWAY_MAX_BODY_BYTES` (default 1 MiB — far above any legitimate payload), both at the HTTP
|
||||
layer (`http.MaxBytesReader`) and as the Connect per-message read limit, so an oversized
|
||||
|
||||
+14
-1
@@ -229,7 +229,10 @@ brief warm-up shows on the first open otherwise — and falls back to the server
|
||||
local dictionary is unavailable. The dictionary check tool is
|
||||
unlimited and offers a complaint on any result; for a word it finds, it also links out to an
|
||||
external reference dictionary (gramota.ru for Russian games, scrabblewordfinder.org for
|
||||
English) to look it up. Hints are governed per game —
|
||||
English) to look it up. While offline in an online game the check runs against the game's own
|
||||
dictionary on the device — the same verdict as the server when that dictionary is available,
|
||||
otherwise it reads *unavailable offline* — and the complaint and the external look-up, which both
|
||||
need the network, are hidden. Hints are governed per game —
|
||||
whether they are allowed and how many each player starts with — and draw on a
|
||||
personal hint wallet once the per-game allowance is spent. Against the robot
|
||||
(**vs_ai**) hints are instead **unlimited and wallet-free**, but idle-gated as an
|
||||
@@ -322,6 +325,16 @@ offline on its own, and restoring the network returns it online by itself. There
|
||||
switch to remember: a brief drop is ridden out quietly and only a sustained loss turns the chrome
|
||||
offline, so you are never interrupted for a hiccup.
|
||||
|
||||
**Losing the connection while inside an online game** is surfaced on **every platform, including the
|
||||
Telegram/VK mini-apps** — unlike the offline-play mode above, which is web/native only — because an
|
||||
online game needs the server for every move. A slim *connection lost* banner appears at the top of the
|
||||
board and the play area **freezes**: the rack, the move controls, the add-friend/block controls and the
|
||||
chat/dictionary entry all disable, while a move you had started stays on the board as a draft. Nothing
|
||||
is sent; when the connection returns the banner clears, the controls come back and you commit the move
|
||||
yourself. If you were already in the chat or the dictionary when the drop happened you stay there — chat
|
||||
becomes read-only (send and nudge disable) and the dictionary keeps checking words against the game's
|
||||
on-device dictionary.
|
||||
|
||||
### Staying up to date
|
||||
When a new client version is required, the app does not lock you out. On the **native** app a
|
||||
too-old build shows a notice with **Update** (opens the store) and **Play offline** (dismiss and keep
|
||||
|
||||
+12
-1
@@ -236,7 +236,9 @@ e-mail) либо ввод фразы. Активные игры форфейтя
|
||||
короткий прогрев, — и уходит на сервер, если локальный словарь недоступен. Инструмент проверки слова безлимитный и
|
||||
предлагает пожаловаться на любой результат; для найденного слова он также даёт ссылку на
|
||||
внешний справочный словарь (gramota.ru для русских игр, scrabblewordfinder.org для английских),
|
||||
чтобы его посмотреть. Подсказки управляются настройками
|
||||
чтобы его посмотреть. В офлайне в онлайн-партии проверка идёт по собственному словарю партии на
|
||||
устройстве — тот же вердикт, что и на сервере, если этот словарь доступен, иначе показывается
|
||||
*недоступно офлайн*, — а жалоба и внешняя ссылка, которым нужна сеть, скрываются. Подсказки управляются настройками
|
||||
партии — разрешены ли они и сколько их у каждого игрока на старте — и расходуют
|
||||
личный кошелёк подсказок после исчерпания внутриигрового лимита. Против робота
|
||||
(**vs_ai**) подсказки, наоборот, **безлимитны и без кошелька**, но с idle-гейтом как
|
||||
@@ -327,6 +329,15 @@ e-mail) либо ввод фразы. Активные игры форфейтя
|
||||
кратковременный сбой пережидается тихо, и только устойчивая потеря переводит интерфейс в офлайн, так что
|
||||
вас не прерывают из-за короткой икоты.
|
||||
|
||||
**Потеря связи внутри онлайн-партии** показывается на **всех платформах, включая мини-приложения
|
||||
Telegram/VK** — в отличие от офлайн-режима игры выше, который только для веба и нативного приложения, —
|
||||
потому что онлайн-партии сервер нужен на каждый ход. Сверху доски появляется тонкий баннер *связь
|
||||
потеряна*, и игровая область **замораживается**: рэк, ходовые кнопки, кнопки «в друзья»/«заблокировать»
|
||||
и вход в чат/словарь отключаются, а начатый ход остаётся на доске черновиком. Ничего не отправляется;
|
||||
когда связь возвращается, баннер исчезает, кнопки оживают, и ход отправляешь ты сам. Если связь упала,
|
||||
когда ты уже был в чате или словаре, ты там и остаёшься — чат становится «только для чтения» (отправка
|
||||
и nudge отключаются), а словарь продолжает проверять слова по словарю партии на устройстве.
|
||||
|
||||
### Актуальная версия
|
||||
Когда требуется новая версия клиента, приложение не блокирует вас наглухо. В **нативном** приложении
|
||||
слишком старая сборка показывает уведомление с **Обновить** (открывает магазин) и **Играть офлайн**
|
||||
|
||||
Reference in New Issue
Block a user