Save call history when peeking and discovering active call links

Co-authored-by: ayumi-signal <143036029+ayumi-signal@users.noreply.github.com>
This commit is contained in:
automated-signal 2024-07-03 17:11:55 -05:00 committed by GitHub
parent e419d00b8c
commit 0cf4f3da7f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 77 additions and 13 deletions

View file

@ -602,6 +602,7 @@ message SyncMessage {
ACCEPTED = 1;
NOT_ACCEPTED = 2;
DELETE = 3;
OBSERVED = 4;
}
/* Data identifying a conversation. The service ID for 1:1, the group ID for

View file

@ -3189,22 +3189,25 @@ export class CallingClass {
const callId = getCallIdFromEra(peekInfo.eraId);
try {
// We only log events confirmed joined. If admin approval is required, then
// the call begins in the Pending state and we don't want history for that.
if (joinState !== GroupCallJoinState.Joined) {
let localCallEvent;
if (joinState === GroupCallJoinState.Joined) {
localCallEvent = LocalCallEvent.Accepted;
} else if (peekInfo && peekInfo.devices.length > 0) {
localCallEvent = LocalCallEvent.Started;
} else {
return;
}
const callDetails = getCallDetailsForAdhocCall(roomId, callId);
const callEvent = getCallEventDetails(
callDetails,
LocalCallEvent.Accepted,
'CallingClass.updateCallHistoryForGroupCallOnLocalChanged'
localCallEvent,
'CallingClass.updateCallHistoryForAdhocCall'
);
await updateAdhocCallHistory(callEvent);
} catch (error) {
log.error(
'CallingClass.updateCallHistoryForGroupCallOnLocalChanged: Error updating state',
'CallingClass.updateCallHistoryForAdhocCall: Error updating state',
Errors.toLogFormat(error)
);
}

View file

@ -536,11 +536,10 @@ const doGroupCallPeek = ({
log.info(`doGroupCallPeek/${logId}: Found ${peekInfo.deviceCount} devices`);
const joinState = isGroupOrAdhocCallState(existingCall)
? existingCall.joinState
: null;
if (callMode === CallMode.Group) {
const joinState = isGroupOrAdhocCallState(existingCall)
? existingCall.joinState
: null;
try {
await calling.updateCallHistoryForGroupCallOnPeek(
conversationId,
@ -555,6 +554,12 @@ const doGroupCallPeek = ({
}
dispatch(updateLastMessage(conversationId));
} else if (callMode === CallMode.Adhoc) {
await calling.updateCallHistoryForAdhocCall(
conversationId,
joinState,
peekInfo
);
}
const formattedPeekInfo = calling.formatGroupCallPeekInfoForRedux(peekInfo);

View file

@ -44,6 +44,7 @@ export enum RemoteCallEvent {
Accepted = 'Accepted',
NotAccepted = 'NotAccepted',
Delete = 'Delete',
Observed = 'Observed',
}
export type CallEvent = LocalCallEvent | RemoteCallEvent;
@ -55,6 +56,7 @@ export enum CallStatusValue {
Declined = 'Declined',
Deleted = 'Deleted',
GenericGroupCall = 'GenericGroupCall',
GenericAdhocCall = 'GenericAdhocCall',
OutgoingRing = 'OutgoingRing',
Ringing = 'Ringing',
Joined = 'Joined',
@ -81,6 +83,7 @@ export enum GroupCallStatus {
}
export enum AdhocCallStatus {
Generic = CallStatusValue.GenericAdhocCall,
Pending = CallStatusValue.Pending,
Joined = CallStatusValue.JoinedAdhoc,
Deleted = CallStatusValue.Deleted,

View file

@ -67,6 +67,7 @@ import {
import type { ConversationType } from '../state/ducks/conversations';
import type { ConversationModel } from '../models/conversations';
import { drop } from './drop';
import { sendCallLinkUpdateSync } from './sendCallLinkUpdateSync';
// utils
// -----
@ -234,6 +235,8 @@ export function getCallEventForProto(
event = RemoteCallEvent.NotAccepted;
} else if (callEvent.event === Proto.SyncMessage.CallEvent.Event.DELETE) {
event = RemoteCallEvent.Delete;
} else if (callEvent.event === Proto.SyncMessage.CallEvent.Event.OBSERVED) {
event = RemoteCallEvent.Observed;
} else {
throw new TypeError(`Unknown call event ${callEvent.event}`);
}
@ -301,6 +304,8 @@ const statusToProto: Record<
[CallStatusValue.Missed]: null,
[CallStatusValue.Pending]: null,
[CallStatusValue.GenericGroupCall]: null,
[CallStatusValue.GenericAdhocCall]:
Proto.SyncMessage.CallEvent.Event.OBSERVED,
[CallStatusValue.OutgoingRing]: null,
[CallStatusValue.Ringing]: null,
[CallStatusValue.Joined]: null,
@ -650,6 +655,15 @@ function transitionTimestamp(
return callHistory.timestamp;
}
// Observed call history should only be changed if we get a remote observed
// event with possibly a better timestamp.
if (callHistory.status === AdhocCallStatus.Generic) {
if (callEvent.event === RemoteCallEvent.Observed) {
return latestTimestamp;
}
return callHistory.timestamp;
}
// Declined call history should only be changed if if we transition to an
// accepted state or get a remote 'not accepted' event with possibly a better
// timestamp.
@ -713,6 +727,12 @@ function transitionDirectCallStatus(
return DirectCallStatus.Missed;
}
if (callEvent === RemoteCallEvent.Observed) {
throw new Error(
`callHistoryDetails: Direct calls shouldn't send ${callEvent}`
);
}
if (callEvent === LocalCallEvent.Missed) {
return DirectCallStatus.Missed;
}
@ -766,7 +786,10 @@ function transitionGroupCallStatus(
return status;
}
if (event === RemoteCallEvent.NotAccepted) {
if (
event === RemoteCallEvent.NotAccepted ||
event === RemoteCallEvent.Observed
) {
throw new Error(`callHistoryDetails: Group calls shouldn't send ${event}`);
}
@ -859,6 +882,13 @@ function transitionAdhocCallStatus(
return status;
}
if (
callEvent === RemoteCallEvent.Observed ||
callEvent === LocalCallEvent.Started
) {
return AdhocCallStatus.Generic;
}
// For Adhoc calls, ringing and corresponding events are not supported currently.
// However we handle those events here to be exhaustive.
if (
@ -867,7 +897,6 @@ function transitionAdhocCallStatus(
callEvent === LocalCallEvent.Declined ||
callEvent === LocalCallEvent.Hangup ||
callEvent === LocalCallEvent.RemoteHangup ||
callEvent === LocalCallEvent.Started ||
// never actually happens, but need for exhaustive check
callEvent === LocalCallEvent.Ringing
) {
@ -985,7 +1014,8 @@ export async function updateLocalAdhocCallHistory(
}
strictAssert(
callHistory.status === AdhocCallStatus.Pending ||
callHistory.status === AdhocCallStatus.Generic ||
callHistory.status === AdhocCallStatus.Pending ||
callHistory.status === AdhocCallStatus.Joined ||
callHistory.status === AdhocCallStatus.Deleted,
`updateAdhocCallHistory: callHistory must have adhoc status (was ${callHistory.status})`
@ -1002,6 +1032,28 @@ export async function updateLocalAdhocCallHistory(
formatCallHistory(callHistory)
);
await window.Signal.Data.saveCallHistory(callHistory);
/*
If we're not a call link admin and this is the first call history for this link,
then it means we clicked someone else's link and discovered it was active. We
sync this newly observed call link so the subsequent call event OBSERVED sync
message refers to a valid call link.
*/
if (prevCallHistory == null) {
const callLink = await window.Signal.Data.getCallLinkByRoomId(
callEvent.peerId
);
if (callLink) {
log.info(
`updateAdhocCallHistory: Syncing new observed call link ${callEvent.peerId}`
);
drop(sendCallLinkUpdateSync(callLink));
} else {
log.error(
`updateAdhocCallHistory: New observed call link missing in DB: ${callEvent.peerId}`
);
}
}
}
if (isDeleted) {