SHA256
Сделать DM body opaque для сервера и улучшить fallback UI
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { addSystemChatMessage, authService, authorizeSession, state } from '../state.js';
|
||||
import { addSignedMessageToChat, authService, authorizeSession, state } from '../state.js';
|
||||
|
||||
const TYPES = {
|
||||
INVITE: 100,
|
||||
@@ -100,6 +100,88 @@ function formatDuration(ms) {
|
||||
return `${sec}с`;
|
||||
}
|
||||
|
||||
function isInviteUndelivered(call) {
|
||||
const wsDelivered = Number(call?.inviteDelivery?.deliveredWsSessions || 0);
|
||||
const pushDelivered = Number(
|
||||
call?.inviteDelivery?.deliveredWebPushSessions
|
||||
|| call?.inviteDelivery?.deliveredFcmSessions
|
||||
|| 0
|
||||
);
|
||||
return (wsDelivered + pushDelivered) <= 0;
|
||||
}
|
||||
|
||||
function buildOutgoingCallSummaryText(call, summaryCode) {
|
||||
if (!call || call.direction !== 'out') return '';
|
||||
if (summaryCode === 'completed') {
|
||||
const duration = formatDuration(nowMs() - Number(call.connectedAtMs || call.startedAtMs || nowMs()));
|
||||
return `Звонок: ${duration}`;
|
||||
}
|
||||
if (summaryCode === 'busy') {
|
||||
return 'Звонил, но недозвонился: абонент занят';
|
||||
}
|
||||
if (summaryCode === 'declined') {
|
||||
return 'Звонил, но недозвонился: звонок отклонён';
|
||||
}
|
||||
if (summaryCode === 'no_answer') {
|
||||
if (isInviteUndelivered(call)) {
|
||||
return 'Звонил, но недозвонился: абонент не в сети';
|
||||
}
|
||||
return 'Звонил, но недозвонился: нет ответа';
|
||||
}
|
||||
if (summaryCode === 'error') {
|
||||
return 'Звонил, но недозвонился: не удалось установить соединение';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
async function applyLocalOutgoingDmCopy(peerLogin, result) {
|
||||
const localOutgoingBlobB64 = String(result?.localOutgoingBlobB64 || '').trim();
|
||||
if (!peerLogin || !localOutgoingBlobB64) return false;
|
||||
try {
|
||||
const parsed = authService.parseSignedMessageBlob(localOutgoingBlobB64);
|
||||
const decrypted = await authService.decryptSignedMessageContent({
|
||||
parsed,
|
||||
login: state.session.login,
|
||||
storagePwd: state.session.storagePwdInMemory,
|
||||
});
|
||||
addSignedMessageToChat({
|
||||
chatId: peerLogin,
|
||||
messageKey: String(result?.outgoingKey || parsed?.messageKey || ''),
|
||||
baseKey: String(result?.baseKey || result?.localBaseKey || parsed?.baseKey || ''),
|
||||
from: 'out',
|
||||
text: String(decrypted?.text || ''),
|
||||
messageType: Number(parsed?.messageType || 2),
|
||||
unread: false,
|
||||
rawBlobB64: localOutgoingBlobB64,
|
||||
revisionTimeMs: Number(parsed?.revisionTimeMs || 0),
|
||||
deleted: Boolean(parsed?.deleted),
|
||||
});
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
async function sendOutgoingCallSummaryDm(call, summaryCode) {
|
||||
if (!call || call.direction !== 'out' || !call.peerLogin) return;
|
||||
const text = buildOutgoingCallSummaryText(call, summaryCode);
|
||||
if (!text) return;
|
||||
const login = String(state?.session?.login || '').trim();
|
||||
const storagePwd = String(state?.session?.storagePwdInMemory || '').trim();
|
||||
if (!login || !storagePwd) return;
|
||||
try {
|
||||
const result = await authService.sendDirectMessage({
|
||||
login,
|
||||
toLogin: call.peerLogin,
|
||||
text,
|
||||
storagePwd,
|
||||
});
|
||||
await applyLocalOutgoingDmCopy(call.peerLogin, result);
|
||||
} catch (error) {
|
||||
await emitDebug(call, 'warn', 'call_summary_dm_failed', toErrorText(error));
|
||||
}
|
||||
}
|
||||
|
||||
function cloneDefaultIceServers() {
|
||||
return DEFAULT_ICE_SERVERS.map((row) => ({ ...row }));
|
||||
}
|
||||
@@ -791,49 +873,6 @@ function startReconnectFlow(call, reason = 'disconnected') {
|
||||
void runAttempt();
|
||||
}
|
||||
|
||||
function pushCallSummary(call, summaryCode) {
|
||||
if (!call?.peerLogin) return;
|
||||
const outgoing = call.direction === 'out';
|
||||
const from = outgoing ? 'out' : 'in';
|
||||
|
||||
if (summaryCode === 'busy') {
|
||||
const text = outgoing
|
||||
? '[Звонок] Исходящий: не дозвонились (занято)'
|
||||
: `[Звонок] Пропущенный входящий от ${call.peerLogin} (занято)`;
|
||||
addSystemChatMessage(call.peerLogin, text, { from, kind: 'call-tech' });
|
||||
return;
|
||||
}
|
||||
if (summaryCode === 'no_answer') {
|
||||
const text = outgoing
|
||||
? '[Звонок] Исходящий: не дозвонились (нет ответа)'
|
||||
: `[Звонок] Пропущенный входящий от ${call.peerLogin}`;
|
||||
addSystemChatMessage(call.peerLogin, text, { from, kind: 'call-tech' });
|
||||
return;
|
||||
}
|
||||
if (summaryCode === 'declined') {
|
||||
const text = outgoing
|
||||
? '[Звонок] Исходящий: не дозвонились (отклонён)'
|
||||
: `[Звонок] Входящий звонок от ${call.peerLogin} отклонён`;
|
||||
addSystemChatMessage(call.peerLogin, text, { from, kind: 'call-tech' });
|
||||
return;
|
||||
}
|
||||
if (summaryCode === 'error') {
|
||||
const text = outgoing
|
||||
? '[Звонок] Исходящий: не дозвонились (ошибка соединения)'
|
||||
: `[Звонок] Входящий звонок от ${call.peerLogin}: ошибка соединения`;
|
||||
addSystemChatMessage(call.peerLogin, text, { from, kind: 'call-tech' });
|
||||
return;
|
||||
}
|
||||
if (summaryCode === 'completed') {
|
||||
const duration = formatDuration(nowMs() - Number(call.connectedAtMs || call.startedAtMs || nowMs()));
|
||||
const label = outgoing ? 'Исходящий' : 'Входящий';
|
||||
addSystemChatMessage(call.peerLogin, `[Звонок] ${label}: разговор ${duration}`, {
|
||||
from,
|
||||
kind: 'call-tech',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function finalizeCall(call, {
|
||||
localReasonCode = 'error',
|
||||
debugReason = '',
|
||||
@@ -902,7 +941,7 @@ async function finalizeCall(call, {
|
||||
}
|
||||
|
||||
if (!suppressSummary) {
|
||||
pushCallSummary(call, localReasonCode);
|
||||
await sendOutgoingCallSummaryDm(call, localReasonCode);
|
||||
}
|
||||
|
||||
call.phase = 'ended';
|
||||
@@ -1424,7 +1463,7 @@ export async function startOutgoingCall(peerLogin) {
|
||||
}, 35000);
|
||||
|
||||
try {
|
||||
await authService.callInviteBroadcast({ toLogin: cleanPeer, callId, type: TYPES.INVITE });
|
||||
call.inviteDelivery = await authService.callInviteBroadcast({ toLogin: cleanPeer, callId, type: TYPES.INVITE });
|
||||
} catch (error) {
|
||||
const text = String(error?.message || '').toUpperCase();
|
||||
const isNotAuth = text.includes('NOT_AUTHENTICATED');
|
||||
@@ -1432,7 +1471,7 @@ export async function startOutgoingCall(peerLogin) {
|
||||
const recovered = await ensureSessionForCall({ timeoutMs: preflightTimeoutMs, force: true });
|
||||
if (recovered) {
|
||||
try {
|
||||
await authService.callInviteBroadcast({ toLogin: cleanPeer, callId, type: TYPES.INVITE });
|
||||
call.inviteDelivery = await authService.callInviteBroadcast({ toLogin: cleanPeer, callId, type: TYPES.INVITE });
|
||||
return;
|
||||
} catch {}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user