feat(update): server push-команда на массовое обновление UI и формат версий

This commit is contained in:
AidarKC
2026-04-23 16:19:00 +03:00
parent 630ba30c27
commit f213e9aa43
10 changed files with 252 additions and 14 deletions
+60 -4
View File
@@ -118,6 +118,7 @@ let connectionNextRetryAtMs = 0;
let connectionCheckInFlight = false;
let wsSessionRestoreInFlight = null;
let uiUpdateReloadScheduled = false;
let pwaUpdateCheckAttempted = false;
setClientErrorTransport((payload) => authService.reportClientError(payload));
initPwaInstallPromptHandling();
@@ -235,20 +236,62 @@ async function triggerImmediateConnectionRetry() {
}
function checkAndReloadIfUiUpdated(remoteHashRaw) {
if (uiUpdateReloadScheduled) return;
const remoteHash = String(remoteHashRaw || '').trim();
if (!remoteHash || !CURRENT_BUILD_HASH || remoteHash === CURRENT_BUILD_HASH) return;
scheduleUiReload({
source: 'version-check',
message: `Обнаружена новая версия UI (через Ping): ${CURRENT_BUILD_HASH} -> ${remoteHash}`,
delayMs: 600,
activateWaitingWorker: true,
});
}
async function refreshServiceWorkers({ activateWaitingWorker = false } = {}) {
if (!('serviceWorker' in navigator)) return;
try {
const registrations = await navigator.serviceWorker.getRegistrations();
await Promise.all(registrations.map(async (registration) => {
try {
await registration.update();
} catch {}
if (activateWaitingWorker && registration.waiting) {
try {
registration.waiting.postMessage({ type: 'SKIP_WAITING' });
} catch {}
}
}));
} catch {
// ignore service worker update failures
}
}
function scheduleUiReload({
source = 'ui-update',
message = 'Запрошено обновление интерфейса',
delayMs = 700,
activateWaitingWorker = true,
} = {}) {
if (uiUpdateReloadScheduled) return;
uiUpdateReloadScheduled = true;
addAppLogEntry({
level: 'info',
source: 'version-check',
message: `Обнаружена новая версия UI (через Ping): ${CURRENT_BUILD_HASH} -> ${remoteHash}`,
source,
message,
});
setConnectionStatus('updating');
void refreshServiceWorkers({ activateWaitingWorker });
const ms = Math.min(15_000, Math.max(200, Number(delayMs || 700)));
window.setTimeout(() => {
window.location.reload();
}, 600);
}, ms);
}
async function tryUpdatePwaOnFirstConnectedPing() {
if (pwaUpdateCheckAttempted) return;
pwaUpdateCheckAttempted = true;
await refreshServiceWorkers({ activateWaitingWorker: false });
}
async function checkConnectionHealth() {
@@ -271,6 +314,7 @@ async function checkConnectionHealth() {
const pingResp = await authService.ws.request('Ping', { ts: Date.now() }, 7000);
const remoteUiBuildHash = pingResp?.payload?.uiBuildHash || pingResp?.uiBuildHash || '';
checkAndReloadIfUiUpdated(remoteUiBuildHash);
await tryUpdatePwaOnFirstConnectedPing();
setConnectionStatus('connected');
} catch {
connectionStatusText = '';
@@ -618,6 +662,18 @@ async function init() {
await terminateCurrentSession({ infoMessage: 'Сессия закрыта с другого устройства.' });
});
authService.onEvent('ForceUiReload', async (evt) => {
const payload = evt?.payload || {};
const reason = String(payload.reason || 'server_debug_api').trim() || 'server_debug_api';
const reloadAfterMs = Number(payload.reloadAfterMs || 700);
scheduleUiReload({
source: 'server-ui-reload',
message: `Сервер запросил обновление UI (${reason})`,
delayMs: reloadAfterMs,
activateWaitingWorker: true,
});
});
authService.onEvent('SignedMessageArrived', async (evt) => {
const payload = evt?.payload || {};
const messageKey = String(payload.messageKey || '').trim();