perf(classroom): инкрементальный поллинг доски, картинки в файлы, ретеншн
#1 Студенческий поллинг: вместо полной перезагрузки доски каждые 2с — лёгкая сигнатура страницы (?meta=1 → maxSeq+count). Если доска совпадает с сервером (обычный случай при живом WS) — ничего не грузим. Полная перезагрузка только при расхождении. Счёт подтверждённых штрихов — по положительным id (без bookkeeping). #2 Картинки-штрихи выносятся в файлы /uploads/classroom (вместо base64 в БД): меньше БД и payload поллинга. Имя с префиксом sessionId. #5 Ретеншн: classroom-cleanup удаляет штрихи+файлы завершённых сессий старше N дней (app_settings.classroom_retention_days, по умолч. 30; 0 = выкл), историю/чат/посещаемость не трогает. Планировщик в server.js. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+16
-5
@@ -4550,8 +4550,17 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Student-side full-sync poll: replaces board state every 2s.
|
||||
Handles missed SSE events for strokes AND clears — no since_seq tricks needed. */
|
||||
/* Кол-во подтверждённых сервером штрихов на доске: у них положительный id
|
||||
(локальные, ещё не отправленные — отрицательный). */
|
||||
function _wbLoadedServerCount() {
|
||||
try { return (_wb && _wb._strokes) ? _wb._strokes.filter(s => s.id > 0).length : 0; }
|
||||
catch (e) { return 0; }
|
||||
}
|
||||
|
||||
/* Student-side poll (2s, страховка к WS/SSE). Сначала тянет лёгкую сигнатуру
|
||||
страницы (maxSeq + count); если доска уже совпадает с сервером (обычный случай
|
||||
при живом WS) — НИЧЕГО не грузит. Полная перезагрузка — только при расхождении
|
||||
(пропущенные при обрыве события, клиры, удаления). */
|
||||
function wbStartPoll() {
|
||||
wbStopPoll();
|
||||
_strokePollTimer = setInterval(async () => {
|
||||
@@ -4559,14 +4568,16 @@
|
||||
const page = _wbCurrentPage;
|
||||
const gen = _wbClearGen;
|
||||
try {
|
||||
const sig = await LS.get(`/api/classroom/${_sessionId}/strokes?page_num=${page}&meta=1`);
|
||||
if (_wbClearGen !== gen || _wbCurrentPage !== page) return;
|
||||
// Доска идентична серверу → пропускаем тяжёлую перезагрузку
|
||||
if (sig && sig.maxSeq === _wbMaxSeq && sig.count === _wbLoadedServerCount()) return;
|
||||
// Расхождение → полная перезагрузка (проверенный путь: корректно отражает клиры/undo/пропуски)
|
||||
const res = await LS.get(`/api/classroom/${_sessionId}/strokes?page_num=${page}`);
|
||||
// Discard if board was cleared or page switched while fetching
|
||||
if (_wbClearGen !== gen || _wbCurrentPage !== page) return;
|
||||
const strokes = res.strokes || [];
|
||||
// Update seq cursor so SSE dedup still works
|
||||
_wbMaxSeq = 0;
|
||||
_wbUpdateMaxSeq(strokes);
|
||||
// Full replace — correctly reflects clears, undos, and any missed events
|
||||
_wb.loadStrokes(strokes);
|
||||
if (res.template) _wb.setTemplate(res.template);
|
||||
wbUpdateThumbnail(page);
|
||||
|
||||
Reference in New Issue
Block a user