Send call messages with conversationJobQueue
Co-authored-by: trevor-signal <trevor@signal.org>
This commit is contained in:
parent
72169820eb
commit
783c71999a
18 changed files with 457 additions and 392 deletions
|
@ -23,9 +23,7 @@ import { generateAci } from '../types/ServiceId';
|
||||||
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
import { getDefaultConversation } from '../test-both/helpers/getDefaultConversation';
|
||||||
import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource';
|
import { fakeGetGroupCallVideoFrameSource } from '../test-both/helpers/fakeGetGroupCallVideoFrameSource';
|
||||||
import { setupI18n } from '../util/setupI18n';
|
import { setupI18n } from '../util/setupI18n';
|
||||||
import type { SafetyNumberProps } from './SafetyNumberChangeDialog';
|
|
||||||
import enMessages from '../../_locales/en/messages.json';
|
import enMessages from '../../_locales/en/messages.json';
|
||||||
import { ThemeType } from '../types/Util';
|
|
||||||
import { StorySendMode } from '../types/Stories';
|
import { StorySendMode } from '../types/Stories';
|
||||||
|
|
||||||
const i18n = setupI18n('en', enMessages);
|
const i18n = setupI18n('en', enMessages);
|
||||||
|
@ -69,7 +67,6 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
declineCall: action('decline-call'),
|
declineCall: action('decline-call'),
|
||||||
getGroupCallVideoFrameSource: (_: string, demuxId: number) =>
|
getGroupCallVideoFrameSource: (_: string, demuxId: number) =>
|
||||||
fakeGetGroupCallVideoFrameSource(demuxId),
|
fakeGetGroupCallVideoFrameSource(demuxId),
|
||||||
getPreferredBadge: () => undefined,
|
|
||||||
getPresentingSources: action('get-presenting-sources'),
|
getPresentingSources: action('get-presenting-sources'),
|
||||||
hangUpActiveCall: action('hang-up-active-call'),
|
hangUpActiveCall: action('hang-up-active-call'),
|
||||||
hasInitialLoadCompleted: true,
|
hasInitialLoadCompleted: true,
|
||||||
|
@ -78,7 +75,6 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
callLink: undefined,
|
callLink: undefined,
|
||||||
isGroupCallRaiseHandEnabled: true,
|
isGroupCallRaiseHandEnabled: true,
|
||||||
isGroupCallReactionsEnabled: true,
|
isGroupCallReactionsEnabled: true,
|
||||||
keyChangeOk: action('key-change-ok'),
|
|
||||||
me: {
|
me: {
|
||||||
...getDefaultConversation({
|
...getDefaultConversation({
|
||||||
color: AvatarColors[0],
|
color: AvatarColors[0],
|
||||||
|
@ -92,7 +88,6 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
renderDeviceSelection: () => <div />,
|
renderDeviceSelection: () => <div />,
|
||||||
renderEmojiPicker: () => <>EmojiPicker</>,
|
renderEmojiPicker: () => <>EmojiPicker</>,
|
||||||
renderReactionPicker: () => <div />,
|
renderReactionPicker: () => <div />,
|
||||||
renderSafetyNumberViewer: (_: SafetyNumberProps) => <div />,
|
|
||||||
sendGroupCallRaiseHand: action('send-group-call-raise-hand'),
|
sendGroupCallRaiseHand: action('send-group-call-raise-hand'),
|
||||||
sendGroupCallReaction: action('send-group-call-reaction'),
|
sendGroupCallReaction: action('send-group-call-reaction'),
|
||||||
setGroupCallVideoRequest: action('set-group-call-video-request'),
|
setGroupCallVideoRequest: action('set-group-call-video-request'),
|
||||||
|
@ -108,7 +103,6 @@ const createProps = (storyProps: Partial<PropsType> = {}): PropsType => ({
|
||||||
stopRingtone: action('stop-ringtone'),
|
stopRingtone: action('stop-ringtone'),
|
||||||
switchToPresentationView: action('switch-to-presentation-view'),
|
switchToPresentationView: action('switch-to-presentation-view'),
|
||||||
switchFromPresentationView: action('switch-from-presentation-view'),
|
switchFromPresentationView: action('switch-from-presentation-view'),
|
||||||
theme: ThemeType.light,
|
|
||||||
toggleParticipants: action('toggle-participants'),
|
toggleParticipants: action('toggle-participants'),
|
||||||
togglePip: action('toggle-pip'),
|
togglePip: action('toggle-pip'),
|
||||||
toggleScreenRecordingPermissionsDialog: action(
|
toggleScreenRecordingPermissionsDialog: action(
|
||||||
|
@ -155,7 +149,6 @@ export function OngoingGroupCall(): JSX.Element {
|
||||||
...getCommonActiveCallData(),
|
...getCommonActiveCallData(),
|
||||||
callMode: CallMode.Group,
|
callMode: CallMode.Group,
|
||||||
connectionState: GroupCallConnectionState.Connected,
|
connectionState: GroupCallConnectionState.Connected,
|
||||||
conversationsWithSafetyNumberChanges: [],
|
|
||||||
conversationsByDemuxId: new Map<number, ConversationType>(),
|
conversationsByDemuxId: new Map<number, ConversationType>(),
|
||||||
deviceCount: 0,
|
deviceCount: 0,
|
||||||
joinState: GroupCallJoinState.Joined,
|
joinState: GroupCallJoinState.Joined,
|
||||||
|
@ -232,35 +225,3 @@ export function CallRequestNeeded(): JSX.Element {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GroupCallSafetyNumberChanged(): JSX.Element {
|
|
||||||
return (
|
|
||||||
<CallManager
|
|
||||||
{...createProps({
|
|
||||||
activeCall: {
|
|
||||||
...getCommonActiveCallData(),
|
|
||||||
callMode: CallMode.Group,
|
|
||||||
connectionState: GroupCallConnectionState.Connected,
|
|
||||||
conversationsWithSafetyNumberChanges: [
|
|
||||||
{
|
|
||||||
...getDefaultConversation({
|
|
||||||
title: 'Aaron',
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
conversationsByDemuxId: new Map<number, ConversationType>(),
|
|
||||||
deviceCount: 0,
|
|
||||||
joinState: GroupCallJoinState.Joined,
|
|
||||||
localDemuxId: 1,
|
|
||||||
maxDevices: 5,
|
|
||||||
groupMembers: [],
|
|
||||||
isConversationTooBigToRing: false,
|
|
||||||
peekedParticipants: [],
|
|
||||||
raisedHands: new Set<number>(),
|
|
||||||
remoteParticipants: [],
|
|
||||||
remoteAudioLevels: new Map<number, number>(),
|
|
||||||
},
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,8 +11,6 @@ import { CallingParticipantsList } from './CallingParticipantsList';
|
||||||
import { CallingSelectPresentingSourcesModal } from './CallingSelectPresentingSourcesModal';
|
import { CallingSelectPresentingSourcesModal } from './CallingSelectPresentingSourcesModal';
|
||||||
import { CallingPip } from './CallingPip';
|
import { CallingPip } from './CallingPip';
|
||||||
import { IncomingCallBar } from './IncomingCallBar';
|
import { IncomingCallBar } from './IncomingCallBar';
|
||||||
import type { SafetyNumberProps } from './SafetyNumberChangeDialog';
|
|
||||||
import { SafetyNumberChangeDialog } from './SafetyNumberChangeDialog';
|
|
||||||
import type {
|
import type {
|
||||||
ActiveCallType,
|
ActiveCallType,
|
||||||
CallingConversationType,
|
CallingConversationType,
|
||||||
|
@ -28,13 +26,11 @@ import {
|
||||||
GroupCallJoinState,
|
GroupCallJoinState,
|
||||||
} from '../types/Calling';
|
} from '../types/Calling';
|
||||||
import type { ConversationType } from '../state/ducks/conversations';
|
import type { ConversationType } from '../state/ducks/conversations';
|
||||||
import type { PreferredBadgeSelectorType } from '../state/selectors/badges';
|
|
||||||
import type {
|
import type {
|
||||||
AcceptCallType,
|
AcceptCallType,
|
||||||
CancelCallType,
|
CancelCallType,
|
||||||
DeclineCallType,
|
DeclineCallType,
|
||||||
GroupCallParticipantInfoType,
|
GroupCallParticipantInfoType,
|
||||||
KeyChangeOkType,
|
|
||||||
SendGroupCallRaiseHandType,
|
SendGroupCallRaiseHandType,
|
||||||
SendGroupCallReactionType,
|
SendGroupCallReactionType,
|
||||||
SetGroupCallVideoRequestType,
|
SetGroupCallVideoRequestType,
|
||||||
|
@ -46,7 +42,7 @@ import type {
|
||||||
} from '../state/ducks/calling';
|
} from '../state/ducks/calling';
|
||||||
import { CallLinkRestrictions } from '../types/CallLink';
|
import { CallLinkRestrictions } from '../types/CallLink';
|
||||||
import type { CallLinkType } from '../types/CallLink';
|
import type { CallLinkType } from '../types/CallLink';
|
||||||
import type { LocalizerType, ThemeType } from '../types/Util';
|
import type { LocalizerType } from '../types/Util';
|
||||||
import { missingCaseError } from '../util/missingCaseError';
|
import { missingCaseError } from '../util/missingCaseError';
|
||||||
import { CallingToastProvider } from './CallingToast';
|
import { CallingToastProvider } from './CallingToast';
|
||||||
import type { SmartReactionPicker } from '../state/smart/ReactionPicker';
|
import type { SmartReactionPicker } from '../state/smart/ReactionPicker';
|
||||||
|
@ -89,15 +85,12 @@ export type PropsType = {
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
demuxId: number
|
demuxId: number
|
||||||
) => VideoFrameSource;
|
) => VideoFrameSource;
|
||||||
getPreferredBadge: PreferredBadgeSelectorType;
|
|
||||||
getPresentingSources: () => void;
|
getPresentingSources: () => void;
|
||||||
incomingCall: DirectIncomingCall | GroupIncomingCall | null;
|
incomingCall: DirectIncomingCall | GroupIncomingCall | null;
|
||||||
keyChangeOk: (_: KeyChangeOkType) => void;
|
|
||||||
renderDeviceSelection: () => JSX.Element;
|
renderDeviceSelection: () => JSX.Element;
|
||||||
renderReactionPicker: (
|
renderReactionPicker: (
|
||||||
props: React.ComponentProps<typeof SmartReactionPicker>
|
props: React.ComponentProps<typeof SmartReactionPicker>
|
||||||
) => JSX.Element;
|
) => JSX.Element;
|
||||||
renderSafetyNumberViewer: (props: SafetyNumberProps) => JSX.Element;
|
|
||||||
startCall: (payload: StartCallType) => void;
|
startCall: (payload: StartCallType) => void;
|
||||||
toggleParticipants: () => void;
|
toggleParticipants: () => void;
|
||||||
acceptCall: (_: AcceptCallType) => void;
|
acceptCall: (_: AcceptCallType) => void;
|
||||||
|
@ -131,7 +124,6 @@ export type PropsType = {
|
||||||
switchToPresentationView: () => void;
|
switchToPresentationView: () => void;
|
||||||
switchFromPresentationView: () => void;
|
switchFromPresentationView: () => void;
|
||||||
hangUpActiveCall: (reason: string) => void;
|
hangUpActiveCall: (reason: string) => void;
|
||||||
theme: ThemeType;
|
|
||||||
togglePip: () => void;
|
togglePip: () => void;
|
||||||
toggleScreenRecordingPermissionsDialog: () => unknown;
|
toggleScreenRecordingPermissionsDialog: () => unknown;
|
||||||
toggleSettings: () => void;
|
toggleSettings: () => void;
|
||||||
|
@ -168,16 +160,13 @@ function ActiveCallManager({
|
||||||
i18n,
|
i18n,
|
||||||
isGroupCallRaiseHandEnabled,
|
isGroupCallRaiseHandEnabled,
|
||||||
isGroupCallReactionsEnabled,
|
isGroupCallReactionsEnabled,
|
||||||
keyChangeOk,
|
|
||||||
getGroupCallVideoFrameSource,
|
getGroupCallVideoFrameSource,
|
||||||
getPreferredBadge,
|
|
||||||
getPresentingSources,
|
getPresentingSources,
|
||||||
me,
|
me,
|
||||||
openSystemPreferencesAction,
|
openSystemPreferencesAction,
|
||||||
renderDeviceSelection,
|
renderDeviceSelection,
|
||||||
renderEmojiPicker,
|
renderEmojiPicker,
|
||||||
renderReactionPicker,
|
renderReactionPicker,
|
||||||
renderSafetyNumberViewer,
|
|
||||||
sendGroupCallRaiseHand,
|
sendGroupCallRaiseHand,
|
||||||
sendGroupCallReaction,
|
sendGroupCallReaction,
|
||||||
setGroupCallVideoRequest,
|
setGroupCallVideoRequest,
|
||||||
|
@ -191,7 +180,6 @@ function ActiveCallManager({
|
||||||
startCall,
|
startCall,
|
||||||
switchToPresentationView,
|
switchToPresentationView,
|
||||||
switchFromPresentationView,
|
switchFromPresentationView,
|
||||||
theme,
|
|
||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
togglePip,
|
togglePip,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
@ -263,10 +251,6 @@ function ActiveCallManager({
|
||||||
}
|
}
|
||||||
}, [callLink, showToast]);
|
}, [callLink, showToast]);
|
||||||
|
|
||||||
const onSafetyNumberDialogCancel = useCallback(() => {
|
|
||||||
hangUpActiveCall('safety number dialog cancel');
|
|
||||||
}, [hangUpActiveCall]);
|
|
||||||
|
|
||||||
let isCallFull: boolean;
|
let isCallFull: boolean;
|
||||||
let showCallLobby: boolean;
|
let showCallLobby: boolean;
|
||||||
let groupMembers:
|
let groupMembers:
|
||||||
|
@ -463,26 +447,6 @@ function ActiveCallManager({
|
||||||
participants={groupCallParticipantsForParticipantsList}
|
participants={groupCallParticipantsForParticipantsList}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
{isGroupOrAdhocActiveCall(activeCall) &&
|
|
||||||
activeCall.conversationsWithSafetyNumberChanges.length ? (
|
|
||||||
<SafetyNumberChangeDialog
|
|
||||||
confirmText={i18n('icu:continueCall')}
|
|
||||||
contacts={[
|
|
||||||
{
|
|
||||||
story: undefined,
|
|
||||||
contacts: activeCall.conversationsWithSafetyNumberChanges,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
getPreferredBadge={getPreferredBadge}
|
|
||||||
i18n={i18n}
|
|
||||||
onCancel={onSafetyNumberDialogCancel}
|
|
||||||
onConfirm={() => {
|
|
||||||
keyChangeOk({ conversationId: activeCall.conversation.id });
|
|
||||||
}}
|
|
||||||
renderSafetyNumber={renderSafetyNumberViewer}
|
|
||||||
theme={theme}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -499,7 +463,6 @@ export function CallManager({
|
||||||
closeNeedPermissionScreen,
|
closeNeedPermissionScreen,
|
||||||
declineCall,
|
declineCall,
|
||||||
getGroupCallVideoFrameSource,
|
getGroupCallVideoFrameSource,
|
||||||
getPreferredBadge,
|
|
||||||
getPresentingSources,
|
getPresentingSources,
|
||||||
hangUpActiveCall,
|
hangUpActiveCall,
|
||||||
hasInitialLoadCompleted,
|
hasInitialLoadCompleted,
|
||||||
|
@ -508,7 +471,6 @@ export function CallManager({
|
||||||
isConversationTooBigToRing,
|
isConversationTooBigToRing,
|
||||||
isGroupCallRaiseHandEnabled,
|
isGroupCallRaiseHandEnabled,
|
||||||
isGroupCallReactionsEnabled,
|
isGroupCallReactionsEnabled,
|
||||||
keyChangeOk,
|
|
||||||
me,
|
me,
|
||||||
notifyForCall,
|
notifyForCall,
|
||||||
openSystemPreferencesAction,
|
openSystemPreferencesAction,
|
||||||
|
@ -517,7 +479,6 @@ export function CallManager({
|
||||||
renderDeviceSelection,
|
renderDeviceSelection,
|
||||||
renderEmojiPicker,
|
renderEmojiPicker,
|
||||||
renderReactionPicker,
|
renderReactionPicker,
|
||||||
renderSafetyNumberViewer,
|
|
||||||
sendGroupCallRaiseHand,
|
sendGroupCallRaiseHand,
|
||||||
sendGroupCallReaction,
|
sendGroupCallReaction,
|
||||||
setGroupCallVideoRequest,
|
setGroupCallVideoRequest,
|
||||||
|
@ -533,7 +494,6 @@ export function CallManager({
|
||||||
stopRingtone,
|
stopRingtone,
|
||||||
switchFromPresentationView,
|
switchFromPresentationView,
|
||||||
switchToPresentationView,
|
switchToPresentationView,
|
||||||
theme,
|
|
||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
togglePip,
|
togglePip,
|
||||||
toggleScreenRecordingPermissionsDialog,
|
toggleScreenRecordingPermissionsDialog,
|
||||||
|
@ -594,20 +554,17 @@ export function CallManager({
|
||||||
changeCallView={changeCallView}
|
changeCallView={changeCallView}
|
||||||
closeNeedPermissionScreen={closeNeedPermissionScreen}
|
closeNeedPermissionScreen={closeNeedPermissionScreen}
|
||||||
getGroupCallVideoFrameSource={getGroupCallVideoFrameSource}
|
getGroupCallVideoFrameSource={getGroupCallVideoFrameSource}
|
||||||
getPreferredBadge={getPreferredBadge}
|
|
||||||
getPresentingSources={getPresentingSources}
|
getPresentingSources={getPresentingSources}
|
||||||
hangUpActiveCall={hangUpActiveCall}
|
hangUpActiveCall={hangUpActiveCall}
|
||||||
i18n={i18n}
|
i18n={i18n}
|
||||||
isGroupCallRaiseHandEnabled={isGroupCallRaiseHandEnabled}
|
isGroupCallRaiseHandEnabled={isGroupCallRaiseHandEnabled}
|
||||||
isGroupCallReactionsEnabled={isGroupCallReactionsEnabled}
|
isGroupCallReactionsEnabled={isGroupCallReactionsEnabled}
|
||||||
keyChangeOk={keyChangeOk}
|
|
||||||
me={me}
|
me={me}
|
||||||
openSystemPreferencesAction={openSystemPreferencesAction}
|
openSystemPreferencesAction={openSystemPreferencesAction}
|
||||||
pauseVoiceNotePlayer={pauseVoiceNotePlayer}
|
pauseVoiceNotePlayer={pauseVoiceNotePlayer}
|
||||||
renderDeviceSelection={renderDeviceSelection}
|
renderDeviceSelection={renderDeviceSelection}
|
||||||
renderEmojiPicker={renderEmojiPicker}
|
renderEmojiPicker={renderEmojiPicker}
|
||||||
renderReactionPicker={renderReactionPicker}
|
renderReactionPicker={renderReactionPicker}
|
||||||
renderSafetyNumberViewer={renderSafetyNumberViewer}
|
|
||||||
sendGroupCallRaiseHand={sendGroupCallRaiseHand}
|
sendGroupCallRaiseHand={sendGroupCallRaiseHand}
|
||||||
sendGroupCallReaction={sendGroupCallReaction}
|
sendGroupCallReaction={sendGroupCallReaction}
|
||||||
setGroupCallVideoRequest={setGroupCallVideoRequest}
|
setGroupCallVideoRequest={setGroupCallVideoRequest}
|
||||||
|
@ -621,7 +578,6 @@ export function CallManager({
|
||||||
startCall={startCall}
|
startCall={startCall}
|
||||||
switchFromPresentationView={switchFromPresentationView}
|
switchFromPresentationView={switchFromPresentationView}
|
||||||
switchToPresentationView={switchToPresentationView}
|
switchToPresentationView={switchToPresentationView}
|
||||||
theme={theme}
|
|
||||||
toggleParticipants={toggleParticipants}
|
toggleParticipants={toggleParticipants}
|
||||||
togglePip={togglePip}
|
togglePip={togglePip}
|
||||||
toggleScreenRecordingPermissionsDialog={
|
toggleScreenRecordingPermissionsDialog={
|
||||||
|
|
|
@ -124,7 +124,6 @@ const createActiveGroupCallProp = (overrideProps: GroupCallOverrideProps) => ({
|
||||||
callMode: CallMode.Group as CallMode.Group,
|
callMode: CallMode.Group as CallMode.Group,
|
||||||
connectionState:
|
connectionState:
|
||||||
overrideProps.connectionState || GroupCallConnectionState.Connected,
|
overrideProps.connectionState || GroupCallConnectionState.Connected,
|
||||||
conversationsWithSafetyNumberChanges: [],
|
|
||||||
conversationsByDemuxId: getConversationsByDemuxId(overrideProps),
|
conversationsByDemuxId: getConversationsByDemuxId(overrideProps),
|
||||||
joinState: GroupCallJoinState.Joined,
|
joinState: GroupCallJoinState.Joined,
|
||||||
localDemuxId: LOCAL_DEMUX_ID,
|
localDemuxId: LOCAL_DEMUX_ID,
|
||||||
|
|
|
@ -131,7 +131,6 @@ export function GroupCall(args: PropsType): JSX.Element {
|
||||||
...getCommonActiveCallData({}),
|
...getCommonActiveCallData({}),
|
||||||
callMode: CallMode.Group as CallMode.Group,
|
callMode: CallMode.Group as CallMode.Group,
|
||||||
connectionState: GroupCallConnectionState.Connected,
|
connectionState: GroupCallConnectionState.Connected,
|
||||||
conversationsWithSafetyNumberChanges: [],
|
|
||||||
conversationsByDemuxId: new Map<number, ConversationType>(),
|
conversationsByDemuxId: new Map<number, ConversationType>(),
|
||||||
groupMembers: times(3, () => getDefaultConversation()),
|
groupMembers: times(3, () => getDefaultConversation()),
|
||||||
isConversationTooBigToRing: false,
|
isConversationTooBigToRing: false,
|
||||||
|
|
|
@ -12,7 +12,9 @@ import { jobQueueDatabaseStore } from './JobQueueDatabaseStore';
|
||||||
import { JOB_STATUS, JobQueue } from './JobQueue';
|
import { JOB_STATUS, JobQueue } from './JobQueue';
|
||||||
|
|
||||||
import { sendNormalMessage } from './helpers/sendNormalMessage';
|
import { sendNormalMessage } from './helpers/sendNormalMessage';
|
||||||
|
import { sendCallingMessage } from './helpers/sendCallingMessage';
|
||||||
import { sendDirectExpirationTimerUpdate } from './helpers/sendDirectExpirationTimerUpdate';
|
import { sendDirectExpirationTimerUpdate } from './helpers/sendDirectExpirationTimerUpdate';
|
||||||
|
import { sendGroupCallUpdate } from './helpers/sendGroupCallUpdate';
|
||||||
import { sendGroupUpdate } from './helpers/sendGroupUpdate';
|
import { sendGroupUpdate } from './helpers/sendGroupUpdate';
|
||||||
import { sendDeleteForEveryone } from './helpers/sendDeleteForEveryone';
|
import { sendDeleteForEveryone } from './helpers/sendDeleteForEveryone';
|
||||||
import { sendDeleteStoryForEveryone } from './helpers/sendDeleteStoryForEveryone';
|
import { sendDeleteStoryForEveryone } from './helpers/sendDeleteStoryForEveryone';
|
||||||
|
@ -51,9 +53,11 @@ import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
|
||||||
// Note: generally, we only want to add to this list. If you do need to change one of
|
// Note: generally, we only want to add to this list. If you do need to change one of
|
||||||
// these values, you'll likely need to write a database migration.
|
// these values, you'll likely need to write a database migration.
|
||||||
export const conversationQueueJobEnum = z.enum([
|
export const conversationQueueJobEnum = z.enum([
|
||||||
|
'CallingMessage',
|
||||||
'DeleteForEveryone',
|
'DeleteForEveryone',
|
||||||
'DeleteStoryForEveryone',
|
'DeleteStoryForEveryone',
|
||||||
'DirectExpirationTimerUpdate',
|
'DirectExpirationTimerUpdate',
|
||||||
|
'GroupCallUpdate',
|
||||||
'GroupUpdate',
|
'GroupUpdate',
|
||||||
'NormalMessage',
|
'NormalMessage',
|
||||||
'NullMessage',
|
'NullMessage',
|
||||||
|
@ -67,6 +71,17 @@ export const conversationQueueJobEnum = z.enum([
|
||||||
]);
|
]);
|
||||||
type ConversationQueueJobEnum = z.infer<typeof conversationQueueJobEnum>;
|
type ConversationQueueJobEnum = z.infer<typeof conversationQueueJobEnum>;
|
||||||
|
|
||||||
|
const callingMessageJobDataSchema = z.object({
|
||||||
|
type: z.literal(conversationQueueJobEnum.enum.CallingMessage),
|
||||||
|
conversationId: z.string(),
|
||||||
|
protoBase64: z.string(),
|
||||||
|
urgent: z.boolean(),
|
||||||
|
// These two are group-only
|
||||||
|
recipients: z.array(serviceIdSchema).optional(),
|
||||||
|
isPartialSend: z.boolean().optional(),
|
||||||
|
});
|
||||||
|
export type CallingMessageJobData = z.infer<typeof callingMessageJobDataSchema>;
|
||||||
|
|
||||||
const deleteForEveryoneJobDataSchema = z.object({
|
const deleteForEveryoneJobDataSchema = z.object({
|
||||||
type: z.literal(conversationQueueJobEnum.enum.DeleteForEveryone),
|
type: z.literal(conversationQueueJobEnum.enum.DeleteForEveryone),
|
||||||
conversationId: z.string(),
|
conversationId: z.string(),
|
||||||
|
@ -108,6 +123,16 @@ export type ExpirationTimerUpdateJobData = z.infer<
|
||||||
typeof expirationTimerUpdateJobDataSchema
|
typeof expirationTimerUpdateJobDataSchema
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
const groupCallUpdateJobDataSchema = z.object({
|
||||||
|
type: z.literal(conversationQueueJobEnum.enum.GroupCallUpdate),
|
||||||
|
conversationId: z.string(),
|
||||||
|
eraId: z.string(),
|
||||||
|
urgent: z.boolean(),
|
||||||
|
});
|
||||||
|
export type GroupCallUpdateJobData = z.infer<
|
||||||
|
typeof groupCallUpdateJobDataSchema
|
||||||
|
>;
|
||||||
|
|
||||||
const groupUpdateJobDataSchema = z.object({
|
const groupUpdateJobDataSchema = z.object({
|
||||||
type: z.literal(conversationQueueJobEnum.enum.GroupUpdate),
|
type: z.literal(conversationQueueJobEnum.enum.GroupUpdate),
|
||||||
conversationId: z.string(),
|
conversationId: z.string(),
|
||||||
|
@ -208,9 +233,11 @@ const receiptsJobDataSchema = z.object({
|
||||||
export type ReceiptsJobData = z.infer<typeof receiptsJobDataSchema>;
|
export type ReceiptsJobData = z.infer<typeof receiptsJobDataSchema>;
|
||||||
|
|
||||||
export const conversationQueueJobDataSchema = z.union([
|
export const conversationQueueJobDataSchema = z.union([
|
||||||
|
callingMessageJobDataSchema,
|
||||||
deleteForEveryoneJobDataSchema,
|
deleteForEveryoneJobDataSchema,
|
||||||
deleteStoryForEveryoneJobDataSchema,
|
deleteStoryForEveryoneJobDataSchema,
|
||||||
expirationTimerUpdateJobDataSchema,
|
expirationTimerUpdateJobDataSchema,
|
||||||
|
groupCallUpdateJobDataSchema,
|
||||||
groupUpdateJobDataSchema,
|
groupUpdateJobDataSchema,
|
||||||
normalMessageSendJobDataSchema,
|
normalMessageSendJobDataSchema,
|
||||||
nullMessageJobDataSchema,
|
nullMessageJobDataSchema,
|
||||||
|
@ -239,6 +266,9 @@ const MAX_RETRY_TIME = durations.DAY;
|
||||||
const MAX_ATTEMPTS = exponentialBackoffMaxAttempts(MAX_RETRY_TIME);
|
const MAX_ATTEMPTS = exponentialBackoffMaxAttempts(MAX_RETRY_TIME);
|
||||||
|
|
||||||
function shouldSendShowCaptcha(type: ConversationQueueJobEnum): boolean {
|
function shouldSendShowCaptcha(type: ConversationQueueJobEnum): boolean {
|
||||||
|
if (type === 'CallingMessage') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (type === 'DeleteForEveryone') {
|
if (type === 'DeleteForEveryone') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -248,6 +278,9 @@ function shouldSendShowCaptcha(type: ConversationQueueJobEnum): boolean {
|
||||||
if (type === 'DirectExpirationTimerUpdate') {
|
if (type === 'DirectExpirationTimerUpdate') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (type === 'GroupCallUpdate') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (type === 'GroupUpdate') {
|
if (type === 'GroupUpdate') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -263,6 +296,9 @@ function shouldSendShowCaptcha(type: ConversationQueueJobEnum): boolean {
|
||||||
if (type === 'Reaction') {
|
if (type === 'Reaction') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (type === 'Receipts') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (type === 'ResendRequest') {
|
if (type === 'ResendRequest') {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -277,9 +313,6 @@ function shouldSendShowCaptcha(type: ConversationQueueJobEnum): boolean {
|
||||||
if (type === 'Story') {
|
if (type === 'Story') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (type === 'Receipts') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw missingCaseError(type);
|
throw missingCaseError(type);
|
||||||
}
|
}
|
||||||
|
@ -785,6 +818,9 @@ export class ConversationJobQueue extends JobQueue<ConversationQueueJobData> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
case jobSet.CallingMessage:
|
||||||
|
await sendCallingMessage(conversation, jobBundle, data);
|
||||||
|
break;
|
||||||
case jobSet.DeleteForEveryone:
|
case jobSet.DeleteForEveryone:
|
||||||
await sendDeleteForEveryone(conversation, jobBundle, data);
|
await sendDeleteForEveryone(conversation, jobBundle, data);
|
||||||
break;
|
break;
|
||||||
|
@ -794,6 +830,9 @@ export class ConversationJobQueue extends JobQueue<ConversationQueueJobData> {
|
||||||
case jobSet.DirectExpirationTimerUpdate:
|
case jobSet.DirectExpirationTimerUpdate:
|
||||||
await sendDirectExpirationTimerUpdate(conversation, jobBundle, data);
|
await sendDirectExpirationTimerUpdate(conversation, jobBundle, data);
|
||||||
break;
|
break;
|
||||||
|
case jobSet.GroupCallUpdate:
|
||||||
|
await sendGroupCallUpdate(conversation, jobBundle, data);
|
||||||
|
break;
|
||||||
case jobSet.GroupUpdate:
|
case jobSet.GroupUpdate:
|
||||||
await sendGroupUpdate(conversation, jobBundle, data);
|
await sendGroupUpdate(conversation, jobBundle, data);
|
||||||
break;
|
break;
|
||||||
|
|
40
ts/jobs/helpers/getValidRecipients.ts
Normal file
40
ts/jobs/helpers/getValidRecipients.ts
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import { isNotNil } from '../../util/isNotNil';
|
||||||
|
|
||||||
|
import type { LoggerType } from '../../types/Logging';
|
||||||
|
import type { ServiceIdString } from '../../types/ServiceId';
|
||||||
|
|
||||||
|
export function getValidRecipients(
|
||||||
|
recipients: Array<string>,
|
||||||
|
options: {
|
||||||
|
logId: string;
|
||||||
|
log: LoggerType;
|
||||||
|
}
|
||||||
|
): Array<ServiceIdString> {
|
||||||
|
const { log, logId } = options;
|
||||||
|
|
||||||
|
return recipients
|
||||||
|
.map(id => {
|
||||||
|
const recipient = window.ConversationController.get(id);
|
||||||
|
if (!recipient) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (recipient.isUnregistered()) {
|
||||||
|
log.warn(
|
||||||
|
`${logId}: dropping unregistered recipient ${recipient.idForLogging()}`
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
if (recipient.isBlocked()) {
|
||||||
|
log.warn(
|
||||||
|
`${logId}: dropping blocked recipient ${recipient.idForLogging()}`
|
||||||
|
);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return recipient.getSendTarget();
|
||||||
|
})
|
||||||
|
.filter(isNotNil);
|
||||||
|
}
|
149
ts/jobs/helpers/sendCallingMessage.ts
Normal file
149
ts/jobs/helpers/sendCallingMessage.ts
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import { handleMessageSend } from '../../util/handleMessageSend';
|
||||||
|
import { getSendOptions } from '../../util/getSendOptions';
|
||||||
|
import {
|
||||||
|
isDirectConversation,
|
||||||
|
isGroup,
|
||||||
|
} from '../../util/whatTypeOfConversation';
|
||||||
|
import { SignalService as Proto } from '../../protobuf';
|
||||||
|
import {
|
||||||
|
handleMultipleSendErrors,
|
||||||
|
maybeExpandErrors,
|
||||||
|
} from './handleMultipleSendErrors';
|
||||||
|
|
||||||
|
import type { ConversationModel } from '../../models/conversations';
|
||||||
|
import type {
|
||||||
|
ConversationQueueJobBundle,
|
||||||
|
CallingMessageJobData,
|
||||||
|
} from '../conversationJobQueue';
|
||||||
|
import { isConversationUnregistered } from '../../util/isConversationUnregistered';
|
||||||
|
import {
|
||||||
|
OutgoingIdentityKeyError,
|
||||||
|
UnregisteredUserError,
|
||||||
|
} from '../../textsecure/Errors';
|
||||||
|
import { getUntrustedConversationServiceIds } from './getUntrustedConversationServiceIds';
|
||||||
|
import { sendContentMessageToGroup } from '../../util/sendToGroup';
|
||||||
|
import * as Bytes from '../../Bytes';
|
||||||
|
import { getValidRecipients } from './getValidRecipients';
|
||||||
|
|
||||||
|
export async function sendCallingMessage(
|
||||||
|
conversation: ConversationModel,
|
||||||
|
{
|
||||||
|
isFinalAttempt,
|
||||||
|
messaging,
|
||||||
|
shouldContinue,
|
||||||
|
timestamp,
|
||||||
|
timeRemaining,
|
||||||
|
log,
|
||||||
|
}: ConversationQueueJobBundle,
|
||||||
|
data: CallingMessageJobData
|
||||||
|
): Promise<void> {
|
||||||
|
const logId = `sendCallingMessage(${conversation.idForLogging()}.${timestamp})`;
|
||||||
|
if (!shouldContinue) {
|
||||||
|
log.info(`${logId}: Ran out of time. Giving up.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`${logId}: Starting send`);
|
||||||
|
|
||||||
|
if (
|
||||||
|
isDirectConversation(conversation.attributes) &&
|
||||||
|
isConversationUnregistered(conversation.attributes)
|
||||||
|
) {
|
||||||
|
log.warn(`${logId}: Direct conversation is unregistered; refusing to send`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const {
|
||||||
|
protoBase64,
|
||||||
|
urgent,
|
||||||
|
recipients: jobRecipients,
|
||||||
|
isPartialSend,
|
||||||
|
} = data;
|
||||||
|
|
||||||
|
const recipients = getValidRecipients(
|
||||||
|
jobRecipients || conversation.getRecipients(),
|
||||||
|
{ log, logId }
|
||||||
|
);
|
||||||
|
|
||||||
|
const untrustedServiceIds = getUntrustedConversationServiceIds(recipients);
|
||||||
|
if (untrustedServiceIds.length) {
|
||||||
|
window.reduxActions.conversations.conversationStoppedByMissingVerification({
|
||||||
|
conversationId: conversation.id,
|
||||||
|
untrustedServiceIds,
|
||||||
|
});
|
||||||
|
throw new Error(
|
||||||
|
`${logId}: Blocked because ${untrustedServiceIds.length} conversation(s) were untrusted. Failing this attempt.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recipients.length === 0) {
|
||||||
|
log.warn(`${logId}: Giving up because there are no valid recipients.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendType = 'callingMessage';
|
||||||
|
const sendOptions = await getSendOptions(conversation.attributes);
|
||||||
|
|
||||||
|
const callingMessage = Proto.CallingMessage.decode(
|
||||||
|
Bytes.fromBase64(protoBase64)
|
||||||
|
);
|
||||||
|
|
||||||
|
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isGroup(conversation.attributes)) {
|
||||||
|
await handleMessageSend(
|
||||||
|
sendContentMessageToGroup({
|
||||||
|
contentHint: ContentHint.DEFAULT,
|
||||||
|
contentMessage: new Proto.Content({ callingMessage }),
|
||||||
|
isPartialSend,
|
||||||
|
messageId: undefined,
|
||||||
|
recipients,
|
||||||
|
sendOptions,
|
||||||
|
sendTarget: conversation.toSenderKeyTarget(),
|
||||||
|
sendType,
|
||||||
|
timestamp,
|
||||||
|
urgent,
|
||||||
|
}),
|
||||||
|
{ messageIds: [], sendType }
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const sendTarget = conversation.getSendTarget();
|
||||||
|
if (!sendTarget) {
|
||||||
|
log.error(`${logId}: Direct conversation send target is falsy`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await handleMessageSend(
|
||||||
|
messaging.sendCallingMessage(
|
||||||
|
sendTarget,
|
||||||
|
callingMessage,
|
||||||
|
timestamp,
|
||||||
|
urgent,
|
||||||
|
sendOptions
|
||||||
|
),
|
||||||
|
{ messageIds: [], sendType }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (error: unknown) {
|
||||||
|
if (
|
||||||
|
error instanceof OutgoingIdentityKeyError ||
|
||||||
|
error instanceof UnregisteredUserError
|
||||||
|
) {
|
||||||
|
log.info(
|
||||||
|
`${logId}: Send failure was OutgoingIdentityKeyError or UnregisteredUserError. Cancelling job.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await handleMultipleSendErrors({
|
||||||
|
errors: maybeExpandErrors(error),
|
||||||
|
isFinalAttempt,
|
||||||
|
log,
|
||||||
|
timeRemaining,
|
||||||
|
toThrow: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
110
ts/jobs/helpers/sendGroupCallUpdate.ts
Normal file
110
ts/jobs/helpers/sendGroupCallUpdate.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
|
import { getSendOptions } from '../../util/getSendOptions';
|
||||||
|
import { isGroup } from '../../util/whatTypeOfConversation';
|
||||||
|
import { SignalService as Proto } from '../../protobuf';
|
||||||
|
import {
|
||||||
|
handleMultipleSendErrors,
|
||||||
|
maybeExpandErrors,
|
||||||
|
} from './handleMultipleSendErrors';
|
||||||
|
|
||||||
|
import type { ConversationModel } from '../../models/conversations';
|
||||||
|
import type {
|
||||||
|
ConversationQueueJobBundle,
|
||||||
|
GroupCallUpdateJobData,
|
||||||
|
} from '../conversationJobQueue';
|
||||||
|
import { getUntrustedConversationServiceIds } from './getUntrustedConversationServiceIds';
|
||||||
|
import { sendToGroup } from '../../util/sendToGroup';
|
||||||
|
import { wrapWithSyncMessageSend } from '../../util/wrapWithSyncMessageSend';
|
||||||
|
import { getValidRecipients } from './getValidRecipients';
|
||||||
|
|
||||||
|
export async function sendGroupCallUpdate(
|
||||||
|
conversation: ConversationModel,
|
||||||
|
{
|
||||||
|
isFinalAttempt,
|
||||||
|
shouldContinue,
|
||||||
|
timestamp,
|
||||||
|
timeRemaining,
|
||||||
|
log,
|
||||||
|
}: ConversationQueueJobBundle,
|
||||||
|
data: GroupCallUpdateJobData
|
||||||
|
): Promise<void> {
|
||||||
|
const { eraId, urgent } = data;
|
||||||
|
const logId = `sendCallUpdate(${conversation.idForLogging()}.${eraId})`;
|
||||||
|
if (!shouldContinue) {
|
||||||
|
log.info(`${logId}: Ran out of time. Giving up.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info(`${logId}: Starting send`);
|
||||||
|
|
||||||
|
if (!isGroup(conversation.attributes)) {
|
||||||
|
log.warn(`${logId}: Conversation is not a group; refusing to send`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recipients = getValidRecipients(conversation.getRecipients(), {
|
||||||
|
log,
|
||||||
|
logId,
|
||||||
|
});
|
||||||
|
|
||||||
|
const untrustedServiceIds = getUntrustedConversationServiceIds(recipients);
|
||||||
|
if (untrustedServiceIds.length) {
|
||||||
|
window.reduxActions.conversations.conversationStoppedByMissingVerification({
|
||||||
|
conversationId: conversation.id,
|
||||||
|
untrustedServiceIds,
|
||||||
|
});
|
||||||
|
throw new Error(
|
||||||
|
`${logId}: Blocked because ${untrustedServiceIds.length} conversation(s) were untrusted. Failing this attempt.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (recipients.length === 0) {
|
||||||
|
log.warn(`${logId}: Giving up because there are no valid recipients.`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sendType = 'callingMessage';
|
||||||
|
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
||||||
|
const groupV2 = conversation.getGroupV2Info();
|
||||||
|
const sendOptions = await getSendOptions(conversation.attributes);
|
||||||
|
if (!groupV2) {
|
||||||
|
log.error(`${logId}: Conversation lacks groupV2 info!`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await wrapWithSyncMessageSend({
|
||||||
|
conversation,
|
||||||
|
logId,
|
||||||
|
messageIds: [],
|
||||||
|
send: () =>
|
||||||
|
conversation.queueJob(logId, () =>
|
||||||
|
sendToGroup({
|
||||||
|
contentHint: ContentHint.DEFAULT,
|
||||||
|
groupSendOptions: {
|
||||||
|
groupCallUpdate: { eraId },
|
||||||
|
groupV2,
|
||||||
|
timestamp,
|
||||||
|
},
|
||||||
|
messageId: undefined,
|
||||||
|
sendOptions,
|
||||||
|
sendTarget: conversation.toSenderKeyTarget(),
|
||||||
|
sendType,
|
||||||
|
urgent,
|
||||||
|
})
|
||||||
|
),
|
||||||
|
sendType,
|
||||||
|
timestamp,
|
||||||
|
});
|
||||||
|
} catch (error: unknown) {
|
||||||
|
await handleMultipleSendErrors({
|
||||||
|
errors: maybeExpandErrors(error),
|
||||||
|
isFinalAttempt,
|
||||||
|
log,
|
||||||
|
timeRemaining,
|
||||||
|
toThrow: error,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,7 +11,6 @@ import {
|
||||||
import { wrapWithSyncMessageSend } from '../../util/wrapWithSyncMessageSend';
|
import { wrapWithSyncMessageSend } from '../../util/wrapWithSyncMessageSend';
|
||||||
import * as Bytes from '../../Bytes';
|
import * as Bytes from '../../Bytes';
|
||||||
import { strictAssert } from '../../util/assert';
|
import { strictAssert } from '../../util/assert';
|
||||||
import { isNotNil } from '../../util/isNotNil';
|
|
||||||
import { ourProfileKeyService } from '../../services/ourProfileKey';
|
import { ourProfileKeyService } from '../../services/ourProfileKey';
|
||||||
|
|
||||||
import type { ConversationModel } from '../../models/conversations';
|
import type { ConversationModel } from '../../models/conversations';
|
||||||
|
@ -22,6 +21,7 @@ import type {
|
||||||
} from '../conversationJobQueue';
|
} from '../conversationJobQueue';
|
||||||
import { getUntrustedConversationServiceIds } from './getUntrustedConversationServiceIds';
|
import { getUntrustedConversationServiceIds } from './getUntrustedConversationServiceIds';
|
||||||
import { sendToGroup } from '../../util/sendToGroup';
|
import { sendToGroup } from '../../util/sendToGroup';
|
||||||
|
import { getValidRecipients } from './getValidRecipients';
|
||||||
|
|
||||||
// Note: because we don't have a recipient map, if some sends fail, we will resend this
|
// Note: because we don't have a recipient map, if some sends fail, we will resend this
|
||||||
// message to folks that got it on the first go-round. This is okay, because receivers
|
// message to folks that got it on the first go-round. This is okay, because receivers
|
||||||
|
@ -55,28 +55,7 @@ export async function sendGroupUpdate(
|
||||||
|
|
||||||
const { groupChangeBase64, recipients: jobRecipients, revision } = data;
|
const { groupChangeBase64, recipients: jobRecipients, revision } = data;
|
||||||
|
|
||||||
const recipients = jobRecipients
|
const recipients = getValidRecipients(jobRecipients, { log, logId });
|
||||||
.map(id => {
|
|
||||||
const recipient = window.ConversationController.get(id);
|
|
||||||
if (!recipient) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (recipient.isUnregistered()) {
|
|
||||||
log.warn(
|
|
||||||
`${logId}: dropping unregistered recipient ${recipient.idForLogging()}`
|
|
||||||
);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
if (recipient.isBlocked()) {
|
|
||||||
log.warn(
|
|
||||||
`${logId}: dropping blocked recipient ${recipient.idForLogging()}`
|
|
||||||
);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return recipient.getSendTarget();
|
|
||||||
})
|
|
||||||
.filter(isNotNil);
|
|
||||||
|
|
||||||
const untrustedServiceIds = getUntrustedConversationServiceIds(recipients);
|
const untrustedServiceIds = getUntrustedConversationServiceIds(recipients);
|
||||||
if (untrustedServiceIds.length) {
|
if (untrustedServiceIds.length) {
|
||||||
|
|
|
@ -3008,15 +3008,9 @@ export class ConversationModel extends window.Backbone
|
||||||
'addKeyChange'
|
'addKeyChange'
|
||||||
);
|
);
|
||||||
|
|
||||||
const isUntrusted = await this.isUntrusted();
|
|
||||||
|
|
||||||
this.trigger('newmessage', model);
|
this.trigger('newmessage', model);
|
||||||
|
|
||||||
const serviceId = this.getServiceId();
|
const serviceId = this.getServiceId();
|
||||||
// Group calls are always with folks that have a serviceId
|
|
||||||
if (isUntrusted && isAciString(serviceId)) {
|
|
||||||
window.reduxActions.calling.keyChanged({ aci: serviceId });
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDirectConversation(this.attributes)) {
|
if (isDirectConversation(this.attributes)) {
|
||||||
window.reduxActions?.safetyNumber.clearSafetyNumber(this.id);
|
window.reduxActions?.safetyNumber.clearSafetyNumber(this.id);
|
||||||
|
|
|
@ -81,9 +81,7 @@ import { dropNull } from '../util/dropNull';
|
||||||
import { getOwn } from '../util/getOwn';
|
import { getOwn } from '../util/getOwn';
|
||||||
import * as durations from '../util/durations';
|
import * as durations from '../util/durations';
|
||||||
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
|
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
|
||||||
import { handleMessageSend } from '../util/handleMessageSend';
|
|
||||||
import { fetchMembershipProof, getMembershipList } from '../groups';
|
import { fetchMembershipProof, getMembershipList } from '../groups';
|
||||||
import { wrapWithSyncMessageSend } from '../util/wrapWithSyncMessageSend';
|
|
||||||
import type { ProcessedEnvelope } from '../textsecure/Types.d';
|
import type { ProcessedEnvelope } from '../textsecure/Types.d';
|
||||||
import { missingCaseError } from '../util/missingCaseError';
|
import { missingCaseError } from '../util/missingCaseError';
|
||||||
import { normalizeGroupCallTimestamp } from '../util/ringrtc/normalizeGroupCallTimestamp';
|
import { normalizeGroupCallTimestamp } from '../util/ringrtc/normalizeGroupCallTimestamp';
|
||||||
|
@ -94,7 +92,6 @@ import {
|
||||||
REQUESTED_VIDEO_FRAMERATE,
|
REQUESTED_VIDEO_FRAMERATE,
|
||||||
} from '../calling/constants';
|
} from '../calling/constants';
|
||||||
import { callingMessageToProto } from '../util/callingMessageToProto';
|
import { callingMessageToProto } from '../util/callingMessageToProto';
|
||||||
import { getSendOptions } from '../util/getSendOptions';
|
|
||||||
import { requestMicrophonePermissions } from '../util/requestMicrophonePermissions';
|
import { requestMicrophonePermissions } from '../util/requestMicrophonePermissions';
|
||||||
import OS from '../util/os/osMain';
|
import OS from '../util/os/osMain';
|
||||||
import { SignalService as Proto } from '../protobuf';
|
import { SignalService as Proto } from '../protobuf';
|
||||||
|
@ -107,7 +104,6 @@ import {
|
||||||
} from './notifications';
|
} from './notifications';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import { assertDev, strictAssert } from '../util/assert';
|
import { assertDev, strictAssert } from '../util/assert';
|
||||||
import { sendContentMessageToGroup, sendToGroup } from '../util/sendToGroup';
|
|
||||||
import {
|
import {
|
||||||
formatLocalDeviceState,
|
formatLocalDeviceState,
|
||||||
formatPeekInfo,
|
formatPeekInfo,
|
||||||
|
@ -130,13 +126,14 @@ import {
|
||||||
} from '../util/callDisposition';
|
} from '../util/callDisposition';
|
||||||
import { isNormalNumber } from '../util/isNormalNumber';
|
import { isNormalNumber } from '../util/isNormalNumber';
|
||||||
import { LocalCallEvent } from '../types/CallDisposition';
|
import { LocalCallEvent } from '../types/CallDisposition';
|
||||||
import { isServiceIdString } from '../types/ServiceId';
|
import { isServiceIdString, type ServiceIdString } from '../types/ServiceId';
|
||||||
import { isInSystemContacts } from '../util/isInSystemContacts';
|
import { isInSystemContacts } from '../util/isInSystemContacts';
|
||||||
import {
|
import {
|
||||||
getRoomIdFromRootKey,
|
getRoomIdFromRootKey,
|
||||||
getCallLinkAuthCredentialPresentation,
|
getCallLinkAuthCredentialPresentation,
|
||||||
} from '../util/callLinks';
|
} from '../util/callLinks';
|
||||||
import { isAdhocCallingEnabled } from '../util/isAdhocCallingEnabled';
|
import { isAdhocCallingEnabled } from '../util/isAdhocCallingEnabled';
|
||||||
|
import { conversationJobQueue } from '../jobs/conversationJobQueue';
|
||||||
|
|
||||||
const {
|
const {
|
||||||
processGroupCallRingCancellation,
|
processGroupCallRingCancellation,
|
||||||
|
@ -1430,53 +1427,36 @@ export class CallingClass {
|
||||||
private async sendGroupCallUpdateMessage(
|
private async sendGroupCallUpdateMessage(
|
||||||
conversationId: string,
|
conversationId: string,
|
||||||
eraId: string
|
eraId: string
|
||||||
): Promise<void> {
|
): Promise<boolean> {
|
||||||
const conversation = window.ConversationController.get(conversationId);
|
const conversation = window.ConversationController.get(conversationId);
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
log.error(
|
log.error('sendGroupCallUpdateMessage: Conversation not found!');
|
||||||
'Unable to send group call update message for non-existent conversation'
|
return false;
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const logId = `sendGroupCallUpdateMessage/${conversation.idForLogging()}`;
|
||||||
|
|
||||||
const groupV2 = conversation.getGroupV2Info();
|
const groupV2 = conversation.getGroupV2Info();
|
||||||
const sendOptions = await getSendOptions(conversation.attributes);
|
|
||||||
if (!groupV2) {
|
if (!groupV2) {
|
||||||
log.error(
|
log.error(`${logId}: Conversation lacks groupV2 info!`);
|
||||||
'Unable to send group call update message for conversation that lacks groupV2 info'
|
return false;
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const timestamp = Date.now();
|
try {
|
||||||
|
await conversationJobQueue.add({
|
||||||
// We "fire and forget" because sending this message is non-essential.
|
type: 'GroupCallUpdate',
|
||||||
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
conversationId: conversation.id,
|
||||||
wrapWithSyncMessageSend({
|
eraId,
|
||||||
conversation,
|
urgent: true,
|
||||||
logId: `sendToGroup/groupCallUpdate/${conversationId}-${eraId}`,
|
});
|
||||||
messageIds: [],
|
return true;
|
||||||
send: () =>
|
} catch (err) {
|
||||||
conversation.queueJob('sendGroupCallUpdateMessage', () =>
|
log.error(
|
||||||
sendToGroup({
|
`${logId}: Failed to queue call update:`,
|
||||||
contentHint: ContentHint.DEFAULT,
|
Errors.toLogFormat(err)
|
||||||
groupSendOptions: {
|
);
|
||||||
groupCallUpdate: { eraId },
|
return false;
|
||||||
groupV2,
|
}
|
||||||
timestamp,
|
|
||||||
},
|
|
||||||
messageId: undefined,
|
|
||||||
sendOptions,
|
|
||||||
sendTarget: conversation.toSenderKeyTarget(),
|
|
||||||
sendType: 'callingMessage',
|
|
||||||
urgent: true,
|
|
||||||
})
|
|
||||||
),
|
|
||||||
sendType: 'callingMessage',
|
|
||||||
timestamp,
|
|
||||||
}).catch(err => {
|
|
||||||
log.error('Failed to send group call update:', Errors.toLogFormat(err));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async acceptDirectCall(
|
async acceptDirectCall(
|
||||||
|
@ -2109,50 +2089,71 @@ export class CallingClass {
|
||||||
private async handleSendCallMessageToGroup(
|
private async handleSendCallMessageToGroup(
|
||||||
groupIdBytes: Buffer,
|
groupIdBytes: Buffer,
|
||||||
data: Buffer,
|
data: Buffer,
|
||||||
urgency: CallMessageUrgency
|
urgency: CallMessageUrgency,
|
||||||
): Promise<void> {
|
overrideRecipients: Array<Buffer> = []
|
||||||
|
): Promise<boolean> {
|
||||||
const groupId = groupIdBytes.toString('base64');
|
const groupId = groupIdBytes.toString('base64');
|
||||||
const conversation = window.ConversationController.get(groupId);
|
const conversation = window.ConversationController.get(groupId);
|
||||||
if (!conversation) {
|
if (!conversation) {
|
||||||
log.error('handleSendCallMessageToGroup(): could not find conversation');
|
log.error('handleSendCallMessageToGroup(): could not find conversation');
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timestamp = Date.now();
|
|
||||||
|
|
||||||
const callingMessage = new CallingMessage();
|
|
||||||
callingMessage.opaque = new OpaqueMessage();
|
|
||||||
callingMessage.opaque.data = data;
|
|
||||||
const contentMessage = new Proto.Content();
|
|
||||||
contentMessage.callingMessage = callingMessageToProto(
|
|
||||||
callingMessage,
|
|
||||||
urgency
|
|
||||||
);
|
|
||||||
|
|
||||||
// If this message isn't droppable, we'll wake up recipient devices. The important one
|
// If this message isn't droppable, we'll wake up recipient devices. The important one
|
||||||
// is the first message to start the call.
|
// is the first message to start the call.
|
||||||
const urgent = urgency === CallMessageUrgency.HandleImmediately;
|
const urgent = urgency === CallMessageUrgency.HandleImmediately;
|
||||||
|
|
||||||
// We "fire and forget" because sending this message is non-essential.
|
try {
|
||||||
// We also don't sync this message.
|
let recipients: Array<ServiceIdString> = [];
|
||||||
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
let isPartialSend = false;
|
||||||
await conversation.queueJob('handleSendCallMessageToGroup', async () =>
|
if (overrideRecipients.length > 0) {
|
||||||
handleMessageSend(
|
// Send only to the overriding recipients.
|
||||||
sendContentMessageToGroup({
|
overrideRecipients.forEach(recipient => {
|
||||||
contentHint: ContentHint.DEFAULT,
|
const serviceId = bytesToUuid(recipient);
|
||||||
contentMessage,
|
if (!serviceId) {
|
||||||
isPartialSend: false,
|
log.error(
|
||||||
messageId: undefined,
|
'handleSendCallMessageToGroup(): missing recipient serviceId'
|
||||||
recipients: conversation.getRecipients(),
|
);
|
||||||
sendOptions: await getSendOptions(conversation.attributes),
|
} else {
|
||||||
sendTarget: conversation.toSenderKeyTarget(),
|
assertDev(
|
||||||
sendType: 'callingMessage',
|
isServiceIdString(serviceId),
|
||||||
timestamp,
|
'remoteServiceId is not a serviceId'
|
||||||
urgent,
|
);
|
||||||
}),
|
recipients.push(serviceId);
|
||||||
{ messageIds: [], sendType: 'callingMessage' }
|
}
|
||||||
)
|
});
|
||||||
);
|
isPartialSend = true;
|
||||||
|
} else {
|
||||||
|
// Send to all members in the group.
|
||||||
|
recipients = conversation.getRecipients();
|
||||||
|
}
|
||||||
|
|
||||||
|
const callingMessage = new CallingMessage();
|
||||||
|
callingMessage.opaque = new OpaqueMessage();
|
||||||
|
callingMessage.opaque.data = data;
|
||||||
|
|
||||||
|
const proto = callingMessageToProto(callingMessage, urgency);
|
||||||
|
const protoBytes = Proto.CallingMessage.encode(proto).finish();
|
||||||
|
const protoBase64 = Bytes.toBase64(protoBytes);
|
||||||
|
|
||||||
|
await conversationJobQueue.add({
|
||||||
|
type: 'CallingMessage',
|
||||||
|
conversationId: conversation.id,
|
||||||
|
protoBase64,
|
||||||
|
urgent,
|
||||||
|
isPartialSend,
|
||||||
|
recipients,
|
||||||
|
});
|
||||||
|
|
||||||
|
log.info('handleSendCallMessageToGroup() completed successfully');
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
const errorString = Errors.toLogFormat(err);
|
||||||
|
log.error(
|
||||||
|
`handleSendCallMessageToGroup() failed to queue job: ${errorString}`
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleGroupCallRingUpdate(
|
private async handleGroupCallRingUpdate(
|
||||||
|
@ -2275,15 +2276,14 @@ export class CallingClass {
|
||||||
message: CallingMessage,
|
message: CallingMessage,
|
||||||
urgency?: CallMessageUrgency
|
urgency?: CallMessageUrgency
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
const conversation = window.ConversationController.get(remoteUserId);
|
assertDev(
|
||||||
const sendOptions = conversation
|
isServiceIdString(remoteUserId),
|
||||||
? await getSendOptions(conversation.attributes)
|
'remoteUserId is not a service id'
|
||||||
: undefined;
|
);
|
||||||
|
const conversation = window.ConversationController.getOrCreate(
|
||||||
if (!window.textsecure.messaging) {
|
remoteUserId,
|
||||||
log.warn('handleOutgoingSignaling() returning false; offline');
|
'private'
|
||||||
return false;
|
);
|
||||||
}
|
|
||||||
|
|
||||||
// We want 1:1 call initiate messages to wake up recipient devices, but not others
|
// We want 1:1 call initiate messages to wake up recipient devices, but not others
|
||||||
const urgent =
|
const urgent =
|
||||||
|
@ -2291,32 +2291,23 @@ export class CallingClass {
|
||||||
Boolean(message.offer);
|
Boolean(message.offer);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
assertDev(
|
const proto = callingMessageToProto(message, urgency);
|
||||||
isServiceIdString(remoteUserId),
|
const protoBytes = Proto.CallingMessage.encode(proto).finish();
|
||||||
'remoteUserId is not a service id'
|
const protoBase64 = Bytes.toBase64(protoBytes);
|
||||||
);
|
|
||||||
const result = await handleMessageSend(
|
|
||||||
window.textsecure.messaging.sendCallingMessage(
|
|
||||||
remoteUserId,
|
|
||||||
callingMessageToProto(message, urgency),
|
|
||||||
urgent,
|
|
||||||
sendOptions
|
|
||||||
),
|
|
||||||
{ messageIds: [], sendType: 'callingMessage' }
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result && result.errors && result.errors.length) {
|
await conversationJobQueue.add({
|
||||||
throw result.errors[0];
|
type: 'CallingMessage',
|
||||||
}
|
conversationId: conversation.id,
|
||||||
|
protoBase64,
|
||||||
|
urgent,
|
||||||
|
});
|
||||||
|
|
||||||
log.info('handleOutgoingSignaling() completed successfully');
|
|
||||||
return true;
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (err && err.errors && err.errors.length > 0) {
|
const errorString = Errors.toLogFormat(err);
|
||||||
log.error(`handleOutgoingSignaling() failed: ${err.errors[0].reason}`);
|
log.error(
|
||||||
} else {
|
`handleOutgoingSignaling() failed to queue job: ${errorString}`
|
||||||
log.error('handleOutgoingSignaling() failed');
|
);
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,6 @@ export type ActiveCallStateType = {
|
||||||
pip: boolean;
|
pip: boolean;
|
||||||
presentingSource?: PresentedSource;
|
presentingSource?: PresentedSource;
|
||||||
presentingSourcesAvailable?: Array<PresentableSource>;
|
presentingSourcesAvailable?: Array<PresentableSource>;
|
||||||
safetyNumberChangedAcis: Array<AciString>;
|
|
||||||
settingsDialogOpen: boolean;
|
settingsDialogOpen: boolean;
|
||||||
showNeedsScreenRecordingPermissionsWarning?: boolean;
|
showNeedsScreenRecordingPermissionsWarning?: boolean;
|
||||||
showParticipantsList: boolean;
|
showParticipantsList: boolean;
|
||||||
|
@ -249,14 +248,6 @@ type HangUpActionPayloadType = ReadonlyDeep<{
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
type KeyChangedType = ReadonlyDeep<{
|
|
||||||
aci: AciString;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type KeyChangeOkType = ReadonlyDeep<{
|
|
||||||
conversationId: string;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
export type IncomingDirectCallType = ReadonlyDeep<{
|
export type IncomingDirectCallType = ReadonlyDeep<{
|
||||||
conversationId: string;
|
conversationId: string;
|
||||||
isVideoCall: boolean;
|
isVideoCall: boolean;
|
||||||
|
@ -579,8 +570,6 @@ const GROUP_CALL_REACTIONS_EXPIRED = 'calling/GROUP_CALL_REACTIONS_EXPIRED';
|
||||||
const HANG_UP = 'calling/HANG_UP';
|
const HANG_UP = 'calling/HANG_UP';
|
||||||
const INCOMING_DIRECT_CALL = 'calling/INCOMING_DIRECT_CALL';
|
const INCOMING_DIRECT_CALL = 'calling/INCOMING_DIRECT_CALL';
|
||||||
const INCOMING_GROUP_CALL = 'calling/INCOMING_GROUP_CALL';
|
const INCOMING_GROUP_CALL = 'calling/INCOMING_GROUP_CALL';
|
||||||
const MARK_CALL_TRUSTED = 'calling/MARK_CALL_TRUSTED';
|
|
||||||
const MARK_CALL_UNTRUSTED = 'calling/MARK_CALL_UNTRUSTED';
|
|
||||||
const OUTGOING_CALL = 'calling/OUTGOING_CALL';
|
const OUTGOING_CALL = 'calling/OUTGOING_CALL';
|
||||||
const PEEK_GROUP_CALL_FULFILLED = 'calling/PEEK_GROUP_CALL_FULFILLED';
|
const PEEK_GROUP_CALL_FULFILLED = 'calling/PEEK_GROUP_CALL_FULFILLED';
|
||||||
const RAISE_HAND_GROUP_CALL = 'calling/RAISE_HAND_GROUP_CALL';
|
const RAISE_HAND_GROUP_CALL = 'calling/RAISE_HAND_GROUP_CALL';
|
||||||
|
@ -725,19 +714,6 @@ type IncomingGroupCallActionType = ReadonlyDeep<{
|
||||||
payload: IncomingGroupCallType;
|
payload: IncomingGroupCallType;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// eslint-disable-next-line local-rules/type-alias-readonlydeep
|
|
||||||
type KeyChangedActionType = {
|
|
||||||
type: 'calling/MARK_CALL_UNTRUSTED';
|
|
||||||
payload: {
|
|
||||||
safetyNumberChangedAcis: Array<AciString>;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
type KeyChangeOkActionType = ReadonlyDeep<{
|
|
||||||
type: 'calling/MARK_CALL_TRUSTED';
|
|
||||||
payload: null;
|
|
||||||
}>;
|
|
||||||
|
|
||||||
type SendGroupCallRaiseHandActionType = ReadonlyDeep<{
|
type SendGroupCallRaiseHandActionType = ReadonlyDeep<{
|
||||||
type: 'calling/RAISE_HAND_GROUP_CALL';
|
type: 'calling/RAISE_HAND_GROUP_CALL';
|
||||||
payload: SendGroupCallRaiseHandType;
|
payload: SendGroupCallRaiseHandType;
|
||||||
|
@ -865,8 +841,6 @@ export type CallingActionType =
|
||||||
| HangUpActionType
|
| HangUpActionType
|
||||||
| IncomingDirectCallActionType
|
| IncomingDirectCallActionType
|
||||||
| IncomingGroupCallActionType
|
| IncomingGroupCallActionType
|
||||||
| KeyChangedActionType
|
|
||||||
| KeyChangeOkActionType
|
|
||||||
| OutgoingCallActionType
|
| OutgoingCallActionType
|
||||||
| PeekGroupCallFulfilledActionType
|
| PeekGroupCallFulfilledActionType
|
||||||
| RefreshIODevicesActionType
|
| RefreshIODevicesActionType
|
||||||
|
@ -1267,56 +1241,6 @@ function hangUpActiveCall(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function keyChanged(
|
|
||||||
payload: KeyChangedType
|
|
||||||
): ThunkAction<void, RootStateType, unknown, KeyChangedActionType> {
|
|
||||||
return (dispatch, getState) => {
|
|
||||||
const state = getState();
|
|
||||||
const { activeCallState } = state.calling;
|
|
||||||
|
|
||||||
const activeCall = getActiveCall(state.calling);
|
|
||||||
if (!activeCall || !activeCallState) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isGroupOrAdhocCallState(activeCall)) {
|
|
||||||
const acisChanged = new Set(activeCallState.safetyNumberChangedAcis);
|
|
||||||
|
|
||||||
// Iterate over each participant to ensure that the service id passed in
|
|
||||||
// matches one of the participants in the group call.
|
|
||||||
activeCall.remoteParticipants.forEach(participant => {
|
|
||||||
if (participant.aci === payload.aci) {
|
|
||||||
acisChanged.add(participant.aci);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const safetyNumberChangedAcis = Array.from(acisChanged);
|
|
||||||
|
|
||||||
if (safetyNumberChangedAcis.length) {
|
|
||||||
dispatch({
|
|
||||||
type: MARK_CALL_UNTRUSTED,
|
|
||||||
payload: {
|
|
||||||
safetyNumberChangedAcis,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function keyChangeOk(
|
|
||||||
payload: KeyChangeOkType
|
|
||||||
): ThunkAction<void, RootStateType, unknown, KeyChangeOkActionType> {
|
|
||||||
return dispatch => {
|
|
||||||
calling.resendGroupCallMediaKeys(payload.conversationId);
|
|
||||||
|
|
||||||
dispatch({
|
|
||||||
type: MARK_CALL_TRUSTED,
|
|
||||||
payload: null,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
function sendGroupCallRaiseHand(
|
function sendGroupCallRaiseHand(
|
||||||
payload: SendGroupCallRaiseHandType
|
payload: SendGroupCallRaiseHandType
|
||||||
): ThunkAction<void, RootStateType, unknown, SendGroupCallRaiseHandActionType> {
|
): ThunkAction<void, RootStateType, unknown, SendGroupCallRaiseHandActionType> {
|
||||||
|
@ -2059,8 +1983,6 @@ export const actions = {
|
||||||
groupCallRaisedHandsChange,
|
groupCallRaisedHandsChange,
|
||||||
groupCallStateChange,
|
groupCallStateChange,
|
||||||
hangUpActiveCall,
|
hangUpActiveCall,
|
||||||
keyChangeOk,
|
|
||||||
keyChanged,
|
|
||||||
onOutgoingVideoCallInConversation,
|
onOutgoingVideoCallInConversation,
|
||||||
onOutgoingAudioCallInConversation,
|
onOutgoingAudioCallInConversation,
|
||||||
openSystemPreferencesAction,
|
openSystemPreferencesAction,
|
||||||
|
@ -2284,7 +2206,6 @@ export function reducer(
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing,
|
outgoingRing,
|
||||||
|
@ -2314,7 +2235,6 @@ export function reducer(
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
|
@ -2343,7 +2263,6 @@ export function reducer(
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
|
@ -2505,7 +2424,6 @@ export function reducer(
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
pip: false,
|
pip: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
|
@ -3182,42 +3100,5 @@ export function reducer(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action.type === MARK_CALL_UNTRUSTED) {
|
|
||||||
const { activeCallState } = state;
|
|
||||||
if (!activeCallState) {
|
|
||||||
log.warn('Cannot mark call as untrusted when there is no active call');
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { safetyNumberChangedAcis } = action.payload;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
activeCallState: {
|
|
||||||
...activeCallState,
|
|
||||||
pip: false,
|
|
||||||
safetyNumberChangedAcis,
|
|
||||||
settingsDialogOpen: false,
|
|
||||||
showParticipantsList: false,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (action.type === MARK_CALL_TRUSTED) {
|
|
||||||
const { activeCallState } = state;
|
|
||||||
if (!activeCallState) {
|
|
||||||
log.warn('Cannot mark call as trusted when there is no active call');
|
|
||||||
return state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
activeCallState: {
|
|
||||||
...activeCallState,
|
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ import { missingCaseError } from '../../util/missingCaseError';
|
||||||
import { viewSyncJobQueue } from '../../jobs/viewSyncJobQueue';
|
import { viewSyncJobQueue } from '../../jobs/viewSyncJobQueue';
|
||||||
import { ReadStatus } from '../../messages/MessageReadStatus';
|
import { ReadStatus } from '../../messages/MessageReadStatus';
|
||||||
import { isIncoming, processBodyRanges } from '../selectors/message';
|
import { isIncoming, processBodyRanges } from '../selectors/message';
|
||||||
import { getActiveCallState } from '../selectors/calling';
|
import { getActiveCall, getActiveCallState } from '../selectors/calling';
|
||||||
import { sendDeleteForEveryoneMessage } from '../../util/sendDeleteForEveryoneMessage';
|
import { sendDeleteForEveryoneMessage } from '../../util/sendDeleteForEveryoneMessage';
|
||||||
import type { ShowToastActionType } from './toast';
|
import type { ShowToastActionType } from './toast';
|
||||||
import { SHOW_TOAST } from './toast';
|
import { SHOW_TOAST } from './toast';
|
||||||
|
@ -2433,7 +2433,15 @@ export function cancelConversationVerification(
|
||||||
});
|
});
|
||||||
|
|
||||||
// Start the blocked conversation queues up again
|
// Start the blocked conversation queues up again
|
||||||
|
const activeCall = getActiveCall(state);
|
||||||
conversationIdsBlocked.forEach(conversationId => {
|
conversationIdsBlocked.forEach(conversationId => {
|
||||||
|
if (
|
||||||
|
activeCall &&
|
||||||
|
activeCall.conversationId === conversationId &&
|
||||||
|
activeCall.callMode === CallMode.Direct
|
||||||
|
) {
|
||||||
|
calling.hangup(conversationId, 'canceled conversation verification');
|
||||||
|
}
|
||||||
conversationJobQueue.resolveVerificationWaiter(conversationId);
|
conversationJobQueue.resolveVerificationWaiter(conversationId);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,7 +9,6 @@ import type {
|
||||||
GroupIncomingCall,
|
GroupIncomingCall,
|
||||||
} from '../../components/CallManager';
|
} from '../../components/CallManager';
|
||||||
import { CallManager } from '../../components/CallManager';
|
import { CallManager } from '../../components/CallManager';
|
||||||
import type { SafetyNumberProps } from '../../components/SafetyNumberChangeDialog';
|
|
||||||
import { isConversationTooBigToRing as getIsConversationTooBigToRing } from '../../conversations/isConversationTooBigToRing';
|
import { isConversationTooBigToRing as getIsConversationTooBigToRing } from '../../conversations/isConversationTooBigToRing';
|
||||||
import * as log from '../../logging/log';
|
import * as log from '../../logging/log';
|
||||||
import { calling as callingService } from '../../services/calling';
|
import { calling as callingService } from '../../services/calling';
|
||||||
|
@ -47,16 +46,14 @@ import type { ConversationType } from '../ducks/conversations';
|
||||||
import { useToastActions } from '../ducks/toast';
|
import { useToastActions } from '../ducks/toast';
|
||||||
import type { StateType } from '../reducer';
|
import type { StateType } from '../reducer';
|
||||||
import { getHasInitialLoadCompleted } from '../selectors/app';
|
import { getHasInitialLoadCompleted } from '../selectors/app';
|
||||||
import { getPreferredBadgeSelector } from '../selectors/badges';
|
|
||||||
import {
|
import {
|
||||||
getAvailableCameras,
|
getAvailableCameras,
|
||||||
getCallLinkSelector,
|
getCallLinkSelector,
|
||||||
getIncomingCall,
|
getIncomingCall,
|
||||||
} from '../selectors/calling';
|
} from '../selectors/calling';
|
||||||
import { getConversationSelector, getMe } from '../selectors/conversations';
|
import { getConversationSelector, getMe } from '../selectors/conversations';
|
||||||
import { getIntl, getTheme } from '../selectors/user';
|
import { getIntl } from '../selectors/user';
|
||||||
import { SmartCallingDeviceSelection } from './CallingDeviceSelection';
|
import { SmartCallingDeviceSelection } from './CallingDeviceSelection';
|
||||||
import { SmartSafetyNumberViewer } from './SafetyNumberViewer';
|
|
||||||
import { renderEmojiPicker } from './renderEmojiPicker';
|
import { renderEmojiPicker } from './renderEmojiPicker';
|
||||||
import { renderReactionPicker } from './renderReactionPicker';
|
import { renderReactionPicker } from './renderReactionPicker';
|
||||||
|
|
||||||
|
@ -64,10 +61,6 @@ function renderDeviceSelection(): JSX.Element {
|
||||||
return <SmartCallingDeviceSelection />;
|
return <SmartCallingDeviceSelection />;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSafetyNumberViewer(props: SafetyNumberProps): JSX.Element {
|
|
||||||
return <SmartSafetyNumberViewer {...props} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
const getGroupCallVideoFrameSource =
|
const getGroupCallVideoFrameSource =
|
||||||
callingService.getGroupCallVideoFrameSource.bind(callingService);
|
callingService.getGroupCallVideoFrameSource.bind(callingService);
|
||||||
|
|
||||||
|
@ -216,7 +209,6 @@ const mapStateToActiveCallProp = (
|
||||||
} satisfies ActiveDirectCallType;
|
} satisfies ActiveDirectCallType;
|
||||||
case CallMode.Group:
|
case CallMode.Group:
|
||||||
case CallMode.Adhoc: {
|
case CallMode.Adhoc: {
|
||||||
const conversationsWithSafetyNumberChanges: Array<ConversationType> = [];
|
|
||||||
const groupMembers: Array<ConversationType> = [];
|
const groupMembers: Array<ConversationType> = [];
|
||||||
const remoteParticipants: Array<GroupCallRemoteParticipantType> = [];
|
const remoteParticipants: Array<GroupCallRemoteParticipantType> = [];
|
||||||
const peekedParticipants: Array<ConversationType> = [];
|
const peekedParticipants: Array<ConversationType> = [];
|
||||||
|
@ -290,22 +282,6 @@ const mapStateToActiveCallProp = (
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (
|
|
||||||
let i = 0;
|
|
||||||
i < activeCallState.safetyNumberChangedAcis.length;
|
|
||||||
i += 1
|
|
||||||
) {
|
|
||||||
const aci = activeCallState.safetyNumberChangedAcis[i];
|
|
||||||
|
|
||||||
const remoteConversation = conversationSelectorByAci(aci);
|
|
||||||
if (!remoteConversation) {
|
|
||||||
log.error('Remote participant has no corresponding conversation');
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
conversationsWithSafetyNumberChanges.push(remoteConversation);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let i = 0; i < peekInfo.acis.length; i += 1) {
|
for (let i = 0; i < peekInfo.acis.length; i += 1) {
|
||||||
const peekedParticipantAci = peekInfo.acis[i];
|
const peekedParticipantAci = peekInfo.acis[i];
|
||||||
|
|
||||||
|
@ -323,7 +299,6 @@ const mapStateToActiveCallProp = (
|
||||||
...baseResult,
|
...baseResult,
|
||||||
callMode: call.callMode,
|
callMode: call.callMode,
|
||||||
connectionState: call.connectionState,
|
connectionState: call.connectionState,
|
||||||
conversationsWithSafetyNumberChanges,
|
|
||||||
conversationsByDemuxId,
|
conversationsByDemuxId,
|
||||||
deviceCount: peekInfo.deviceCount,
|
deviceCount: peekInfo.deviceCount,
|
||||||
groupMembers,
|
groupMembers,
|
||||||
|
@ -422,11 +397,9 @@ const mapStateToIncomingCallProp = (
|
||||||
|
|
||||||
export const SmartCallManager = memo(function SmartCallManager() {
|
export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
const i18n = useSelector(getIntl);
|
const i18n = useSelector(getIntl);
|
||||||
const theme = useSelector(getTheme);
|
|
||||||
const activeCall = useSelector(mapStateToActiveCallProp);
|
const activeCall = useSelector(mapStateToActiveCallProp);
|
||||||
const callLink = useSelector(mapStateToCallLinkProp);
|
const callLink = useSelector(mapStateToCallLinkProp);
|
||||||
const incomingCall = useSelector(mapStateToIncomingCallProp);
|
const incomingCall = useSelector(mapStateToIncomingCallProp);
|
||||||
const getPreferredBadge = useSelector(getPreferredBadgeSelector);
|
|
||||||
const availableCameras = useSelector(getAvailableCameras);
|
const availableCameras = useSelector(getAvailableCameras);
|
||||||
const hasInitialLoadCompleted = useSelector(getHasInitialLoadCompleted);
|
const hasInitialLoadCompleted = useSelector(getHasInitialLoadCompleted);
|
||||||
const me = useSelector(getMe);
|
const me = useSelector(getMe);
|
||||||
|
@ -439,7 +412,6 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
closeNeedPermissionScreen,
|
closeNeedPermissionScreen,
|
||||||
getPresentingSources,
|
getPresentingSources,
|
||||||
cancelCall,
|
cancelCall,
|
||||||
keyChangeOk,
|
|
||||||
startCall,
|
startCall,
|
||||||
toggleParticipants,
|
toggleParticipants,
|
||||||
acceptCall,
|
acceptCall,
|
||||||
|
@ -478,7 +450,6 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
closeNeedPermissionScreen={closeNeedPermissionScreen}
|
closeNeedPermissionScreen={closeNeedPermissionScreen}
|
||||||
declineCall={declineCall}
|
declineCall={declineCall}
|
||||||
getGroupCallVideoFrameSource={getGroupCallVideoFrameSource}
|
getGroupCallVideoFrameSource={getGroupCallVideoFrameSource}
|
||||||
getPreferredBadge={getPreferredBadge}
|
|
||||||
getPresentingSources={getPresentingSources}
|
getPresentingSources={getPresentingSources}
|
||||||
hangUpActiveCall={hangUpActiveCall}
|
hangUpActiveCall={hangUpActiveCall}
|
||||||
hasInitialLoadCompleted={hasInitialLoadCompleted}
|
hasInitialLoadCompleted={hasInitialLoadCompleted}
|
||||||
|
@ -487,7 +458,6 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
isConversationTooBigToRing={isConversationTooBigToRing}
|
isConversationTooBigToRing={isConversationTooBigToRing}
|
||||||
isGroupCallRaiseHandEnabled={isGroupCallRaiseHandEnabled()}
|
isGroupCallRaiseHandEnabled={isGroupCallRaiseHandEnabled()}
|
||||||
isGroupCallReactionsEnabled={isGroupCallReactionsEnabled()}
|
isGroupCallReactionsEnabled={isGroupCallReactionsEnabled()}
|
||||||
keyChangeOk={keyChangeOk}
|
|
||||||
me={me}
|
me={me}
|
||||||
notifyForCall={notifyForCall}
|
notifyForCall={notifyForCall}
|
||||||
openSystemPreferencesAction={openSystemPreferencesAction}
|
openSystemPreferencesAction={openSystemPreferencesAction}
|
||||||
|
@ -496,7 +466,6 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
renderDeviceSelection={renderDeviceSelection}
|
renderDeviceSelection={renderDeviceSelection}
|
||||||
renderEmojiPicker={renderEmojiPicker}
|
renderEmojiPicker={renderEmojiPicker}
|
||||||
renderReactionPicker={renderReactionPicker}
|
renderReactionPicker={renderReactionPicker}
|
||||||
renderSafetyNumberViewer={renderSafetyNumberViewer}
|
|
||||||
sendGroupCallRaiseHand={sendGroupCallRaiseHand}
|
sendGroupCallRaiseHand={sendGroupCallRaiseHand}
|
||||||
sendGroupCallReaction={sendGroupCallReaction}
|
sendGroupCallReaction={sendGroupCallReaction}
|
||||||
setGroupCallVideoRequest={setGroupCallVideoRequest}
|
setGroupCallVideoRequest={setGroupCallVideoRequest}
|
||||||
|
@ -512,7 +481,6 @@ export const SmartCallManager = memo(function SmartCallManager() {
|
||||||
stopRingtone={stopRingtone}
|
stopRingtone={stopRingtone}
|
||||||
switchFromPresentationView={switchFromPresentationView}
|
switchFromPresentationView={switchFromPresentationView}
|
||||||
switchToPresentationView={switchToPresentationView}
|
switchToPresentationView={switchToPresentationView}
|
||||||
theme={theme}
|
|
||||||
toggleParticipants={toggleParticipants}
|
toggleParticipants={toggleParticipants}
|
||||||
togglePip={togglePip}
|
togglePip={togglePip}
|
||||||
toggleScreenRecordingPermissionsDialog={
|
toggleScreenRecordingPermissionsDialog={
|
||||||
|
|
|
@ -70,7 +70,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
@ -153,7 +152,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
@ -482,7 +480,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
@ -577,7 +574,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
@ -1198,7 +1194,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
outgoingRing: false,
|
outgoingRing: false,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
@ -1887,7 +1882,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
|
@ -2195,7 +2189,6 @@ describe('calling duck', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
|
|
|
@ -69,7 +69,6 @@ describe('state/selectors/calling', () => {
|
||||||
localAudioLevel: 0,
|
localAudioLevel: 0,
|
||||||
viewMode: CallViewMode.Paginated,
|
viewMode: CallViewMode.Paginated,
|
||||||
showParticipantsList: false,
|
showParticipantsList: false,
|
||||||
safetyNumberChangedAcis: [],
|
|
||||||
outgoingRing: true,
|
outgoingRing: true,
|
||||||
pip: false,
|
pip: false,
|
||||||
settingsDialogOpen: false,
|
settingsDialogOpen: false,
|
||||||
|
|
|
@ -1722,11 +1722,11 @@ export default class MessageSender {
|
||||||
async sendCallingMessage(
|
async sendCallingMessage(
|
||||||
serviceId: ServiceIdString,
|
serviceId: ServiceIdString,
|
||||||
callingMessage: Readonly<Proto.ICallingMessage>,
|
callingMessage: Readonly<Proto.ICallingMessage>,
|
||||||
|
timestamp: number,
|
||||||
urgent: boolean,
|
urgent: boolean,
|
||||||
options?: Readonly<SendOptionsType>
|
options?: Readonly<SendOptionsType>
|
||||||
): Promise<CallbackResultType> {
|
): Promise<CallbackResultType> {
|
||||||
const recipients = [serviceId];
|
const recipients = [serviceId];
|
||||||
const finalTimestamp = Date.now();
|
|
||||||
|
|
||||||
const contentMessage = new Proto.Content();
|
const contentMessage = new Proto.Content();
|
||||||
contentMessage.callingMessage = callingMessage;
|
contentMessage.callingMessage = callingMessage;
|
||||||
|
@ -1736,13 +1736,13 @@ export default class MessageSender {
|
||||||
addPniSignatureMessageToProto({
|
addPniSignatureMessageToProto({
|
||||||
conversation,
|
conversation,
|
||||||
proto: contentMessage,
|
proto: contentMessage,
|
||||||
reason: `sendCallingMessage(${finalTimestamp})`,
|
reason: `sendCallingMessage(${timestamp})`,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
const { ContentHint } = Proto.UnidentifiedSenderMessage.Message;
|
||||||
|
|
||||||
return this.sendMessageProtoAndWait({
|
return this.sendMessageProtoAndWait({
|
||||||
timestamp: finalTimestamp,
|
timestamp,
|
||||||
recipients,
|
recipients,
|
||||||
proto: contentMessage,
|
proto: contentMessage,
|
||||||
contentHint: ContentHint.DEFAULT,
|
contentHint: ContentHint.DEFAULT,
|
||||||
|
|
|
@ -90,7 +90,6 @@ export type ActiveGroupCallType = ActiveCallBaseType & {
|
||||||
callMode: CallMode.Group | CallMode.Adhoc;
|
callMode: CallMode.Group | CallMode.Adhoc;
|
||||||
connectionState: GroupCallConnectionState;
|
connectionState: GroupCallConnectionState;
|
||||||
conversationsByDemuxId: ConversationsByDemuxIdType;
|
conversationsByDemuxId: ConversationsByDemuxIdType;
|
||||||
conversationsWithSafetyNumberChanges: Array<ConversationType>;
|
|
||||||
joinState: GroupCallJoinState;
|
joinState: GroupCallJoinState;
|
||||||
localDemuxId: number | undefined;
|
localDemuxId: number | undefined;
|
||||||
maxDevices: number;
|
maxDevices: number;
|
||||||
|
|
Loading…
Add table
Reference in a new issue