WIP: новая схема сообщений и push (не проверено)

This commit is contained in:
AidarKC
2026-04-19 20:41:58 +03:00
parent f0b560ec06
commit cc59bd18ee
27 changed files with 1668 additions and 94 deletions
+85 -36
View File
@@ -7,13 +7,15 @@ import {
authService,
addAppLogEntry,
authorizeSession,
hydrateMessagesFromStore,
isSessionInvalidError,
refreshSessions,
setSessionAuthorizedHandler,
setSessionResetHandler,
state,
terminateCurrentSession,
addIncomingMessage,
addSignedMessageToChat,
markOutgoingReadByBaseKey,
setContacts,
} from './state.js';
@@ -338,48 +340,94 @@ async function init() {
await terminateCurrentSession({ infoMessage: 'Сессия закрыта с другого устройства.' });
});
authService.onEvent('IncomingDirectMessage', async (evt) => {
authService.onEvent('SignedMessageArrived', async (evt) => {
const payload = evt?.payload || {};
const fromLogin = payload.fromLogin || 'unknown';
const messageId = payload.messageId || '';
const eventId = payload.eventId || evt?.requestId || '';
let text = payload.text || '';
if (!text && payload.blobB64) {
try {
const bytes = Uint8Array.from(atob(payload.blobB64), (ch) => ch.charCodeAt(0));
const msgLen = (bytes[bytes.length - 66] << 8) | bytes[bytes.length - 65];
const msgStart = bytes.length - 64 - msgLen;
const msgBytes = bytes.slice(msgStart, msgStart + msgLen);
text = new TextDecoder().decode(msgBytes);
} catch {
text = '[binary message]';
}
}
const added = addIncomingMessage(fromLogin, text, messageId);
if (added) {
const messageKey = String(payload.messageKey || '').trim();
const blobB64 = String(payload.blobB64 || '').trim();
if (!messageKey || !blobB64) return;
let parsed;
try {
parsed = authService.parseSignedMessageBlob(blobB64);
} catch (error) {
addAppLogEntry({
level: 'info',
source: 'incoming-dm',
message: `Входящее сообщение от ${fromLogin}`,
details: { messageId, text },
level: 'warn',
source: 'signed-dm',
message: 'Не удалось распарсить входящий signed message',
details: { messageKey, error: error?.message || 'unknown' },
});
return;
}
if (added && Notification.permission === 'granted') {
try {
new Notification(`Сообщение от ${fromLogin}`, { body: text || '' });
} catch {}
}
if (eventId) {
try {
await authService.ackIncomingMessage(eventId, messageId);
} catch (error) {
const myLogin = String(state.session.login || '').trim().toLowerCase();
const fromLogin = parsed.fromLogin || '';
const toLogin = parsed.toLogin || '';
const chatId = String(fromLogin || '').toLowerCase() === myLogin ? toLogin : fromLogin;
const messageType = Number(parsed.messageType || 0);
const text = (messageType === 1 || messageType === 2)
? new TextDecoder().decode(parsed.payloadBytes || new Uint8Array(0))
: '';
if (messageType === 1 || messageType === 2) {
const isIncomingForCurrent = messageType === 1;
const added = addSignedMessageToChat({
chatId,
messageKey,
baseKey: parsed.baseKey,
from: isIncomingForCurrent ? 'in' : 'out',
text,
messageType,
unread: isIncomingForCurrent,
rawBlobB64: blobB64,
});
if (added) {
addAppLogEntry({
level: 'warn',
source: 'incoming-dm',
message: 'Не удалось отправить ACK на входящее сообщение',
details: { eventId, messageId, error: error?.message || 'unknown' },
level: 'info',
source: 'signed-dm',
message: isIncomingForCurrent
? `Новое входящее сообщение от ${fromLogin}`
: `Синхронизирована исходящая копия в чате ${chatId}`,
details: { messageKey, baseKey: parsed.baseKey, messageType },
});
}
if (added && isIncomingForCurrent && Notification.permission === 'granted' && !payload.backlog) {
try {
new Notification(`Сообщение от ${fromLogin}`, { body: text || '' });
} catch {}
}
} else if (messageType === 3 || messageType === 4) {
const refBaseKey = String(payload.receiptRefBaseKey || '').trim();
if (refBaseKey) {
markOutgoingReadByBaseKey(refBaseKey);
} else {
try {
const ref = authService.parseReadReceiptPayload(parsed.payloadBytes);
const fallbackRefBase = `${ref.refFromLogin}|${ref.refToLogin}|${ref.refTimeMs}|${ref.refNonce}`;
markOutgoingReadByBaseKey(fallbackRefBase);
} catch {}
}
addAppLogEntry({
level: 'info',
source: 'signed-dm',
message: 'Получено подтверждение прочтения',
details: { messageKey, baseKey: parsed.baseKey, messageType },
});
}
try {
await authService.ackSessionDelivery(messageKey);
} catch (error) {
addAppLogEntry({
level: 'warn',
source: 'signed-dm',
message: 'Не удалось отправить ACK доставки по сессии',
details: { messageKey, error: error?.message || 'unknown' },
});
}
const pageId = getRoute().pageId || '';
if (pageId === 'chat-view' || pageId === 'messages-list') {
renderApp();
}
});
@@ -392,6 +440,7 @@ async function init() {
});
await tryAutoLogin();
await hydrateMessagesFromStore();
await ensureSessionRuntimeStarted();
if (!window.location.hash) {