fix vc desync

This commit is contained in:
olcxja 2026-08-26 09:46:57 +02:00
commit 6a14104143
4 changed files with 314 additions and 82 deletions

View file

@ -4206,6 +4206,55 @@ function handleChatInputKey(event) {
let dmMessagePollInterval = null;
let appWebSocket = null;
let dmMessageLoadTimeout = null;
let appWsPingTimer = null;
let callStatesResyncTimer = null;
//Keepalive app-WS: tekstowy "ping" co 20 s. Serwer zamyka połączenie po 75 s
//bezczynności (AppWsIdleTimeout) - bez tego half-open TCP po zabiciu aplikacji /
//zmianie sieci wisiał na serwerze godzinami, cleanup ActiveCalls nie biegł i
//wskaźniki rozmów pokazywały uczestników, którzy dawno wyszli. Ping utrzymuje
//też mapping NAT przy danych komórkowych, więc eventy (call_update!) nie giną.
function startAppWsPing() {
if (appWsPingTimer) clearInterval(appWsPingTimer);
appWsPingTimer = setInterval(() => {
if (appWebSocket && appWebSocket.readyState === WebSocket.OPEN) {
try { appWebSocket.send("ping"); } catch (e) {}
}
}, 20000);
}
function stopAppWsPing() {
if (appWsPingTimer) { clearInterval(appWsPingTimer); appWsPingTimer = null; }
}
//Pełna resynchronizacja wskaźników rozmów: zgubiony podczas przerwy w app-WS
//call_update NIGDY nie jest odtwarzany przez serwer, a seedCallStateFromList
//tylko dodaje wpisy - bez tego wskaźniki "znikały dopiero po ręcznym odświeżeniu".
//Dla każdego pokoju znanego jako aktywny (+ otwartego) pyta room/voice/state
//i koryguje mapę oraz UI. Uruchamiane: po (re)otwarciu WS, co 30 s, przy powrocie
//karty/aplikacji na wierzch.
async function resyncAllCallStates() {
if (!window.id || typeof fetchEncrypted !== "function" || typeof ensureActiveCallsMap !== "function") return;
let map = ensureActiveCallsMap();
let keys = Object.keys(map);
let currentKey = window.currentDmId ? sanitizeId(window.currentDmId) : null;
if (currentKey && !keys.includes(currentKey)) keys.push(currentKey);
if (keys.length === 0) return;
for (let key of keys) {
let roomType = window.currentDmId === key && window.currentRoomType ? window.currentRoomType
: (String(key).includes("_") ? "dms" : "groups");
try {
let res = await fetchEncrypted("room/voice/state", JSON.stringify({ string1: roomType, string2: key }));
if (!res || !res.startsWith("[")) continue;
let participants = JSON.parse(res).map(u => String(u).split(";")[0]);
if (participants.length > 0) map[key] = participants;
else delete map[key];
} catch (e) {}
}
//Po serii poprawek pełne przerysowanie wskaźników (listy + top-bary + details)
if (typeof updateVoicePresenceUI === "function") updateVoicePresenceUI();
}
function setupWebSocket() {
if (appWebSocket && (appWebSocket.readyState === WebSocket.OPEN || appWebSocket.readyState === WebSocket.CONNECTING)) return;
@ -4228,6 +4277,17 @@ function setupWebSocket() {
} finally {
release();
}
startAppWsPing();
//Po każdym (re)połączeniu odtwarzamy stan wskaźników - eventy call_update
//z czasu rozłączenia są bezpowrotnie stracone
resyncAllCallStates();
if (!callStatesResyncTimer) {
callStatesResyncTimer = setInterval(() => {
if (document.visibilityState !== "visible") return;
resyncAllCallStates();
}, 30000);
}
};
appWebSocket.onmessage = (event) => {
@ -4273,10 +4333,22 @@ function setupWebSocket() {
};
appWebSocket.onclose = () => {
stopAppWsPing();
setTimeout(setupWebSocket, 5000);
};
}
//Powrót karty/aplikacji na wierzch: mobilne WebView potrafią trzymać martwy
//socket odkryty bardzo długo (brak ramek = brak detekcji). Wymuszamy próbę
//połączenia i od razu resynchronizujemy wskaźniki rozmów.
document.addEventListener("visibilitychange", () => {
if (document.visibilityState !== "visible") return;
if (appWebSocket && appWebSocket.readyState !== WebSocket.OPEN && appWebSocket.readyState !== WebSocket.CONNECTING) {
setupWebSocket();
}
resyncAllCallStates();
});
let currentContextMenuMsgId = null;
let touchContextMenuFired = false;