Skip to content

Commit

Permalink
check missing clients on requestClients
Browse files Browse the repository at this point in the history
  • Loading branch information
AndyLnd committed Aug 4, 2020
1 parent a38e799 commit 6f78c91
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 30 deletions.
91 changes: 71 additions & 20 deletions src/script/calling/CallingRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import axios, {AxiosError} from 'axios';
import type {APIClient} from '@wireapp/api-client';
import type {WebappProperties} from '@wireapp/api-client/dist/user/data';
import type {CallConfigData} from '@wireapp/api-client/dist/account/CallConfigData';
import type {NewOTRMessage} from '@wireapp/api-client/dist/conversation';
import type {NewOTRMessage, ClientMismatch, UserClients} from '@wireapp/api-client/dist/conversation';
import {
CALL_TYPE,
CONV_TYPE,
Expand Down Expand Up @@ -247,19 +247,55 @@ export class CallingRepository {
try {
await this.apiClient.conversation.api.postOTRMessage(this.selfClientId, conversationId);
} catch (error) {
const mismatch = (error as AxiosError).response!.data;
const eventInfoEntity = new EventInfoEntity(undefined, conversationId);
type ClientListEntry = [string, string];
const mismatch: ClientMismatch = (error as AxiosError).response!.data;
const localClients: UserClients = await this.conversationRepository.create_recipients(conversationId);

const makeClientList = (recipients: UserClients): ClientListEntry[] =>
Object.entries(recipients).reduce(
(acc, [userId, clients]) => acc.concat(clients.map(clientId => [userId, clientId])),
[],
);

const isSameEntry = ([userA, clientA]: ClientListEntry, [userB, clientB]: ClientListEntry): boolean =>
userA === userB && clientA === clientB;

const fromClientList = (clientList: ClientListEntry[]): UserClients =>
clientList.reduce(
(acc, [userId, clientId]) => ({...acc, [userId]: [...(acc[userId] || []), clientId]}),
{} as UserClients,
);
const localClientList = makeClientList(localClients);
const remoteClientList = makeClientList(mismatch.missing);
const missingClients = remoteClientList.filter(
remoteClient => !localClientList.some(localClient => isSameEntry(remoteClient, localClient)),
);
const deletedClients = localClientList.filter(
localClient => !remoteClientList.some(remoteClient => isSameEntry(remoteClient, localClient)),
);
const localMismatch: ClientMismatch = {
deleted: fromClientList(deletedClients),
missing: fromClientList(missingClients),
redundant: {},
time: mismatch.time,
};

const genericMessage = new GenericMessage({
[GENERIC_MESSAGE_TYPE.CALLING]: new Calling({content: ''}),
messageId: createRandomUuid(),
});
const eventInfoEntity = new EventInfoEntity(genericMessage, conversationId);
eventInfoEntity.setType(GENERIC_MESSAGE_TYPE.CALLING);
const payload: NewOTRMessage = {
native_push: true,
recipients: {},
sender: this.selfClientId,
};
await this.conversationRepository.clientMismatchHandler.onClientMismatch(eventInfoEntity, mismatch, payload);
await this.conversationRepository.clientMismatchHandler.onClientMismatch(eventInfoEntity, localMismatch, payload);

type Clients = {clientid: string; userid: string}[];

const clients: Clients[] = mismatch.missing.map(([userid, clientids]: [string, string[]]) =>
const clients: Clients[] = Object.entries(mismatch.missing).map(([userid, clientids]: [string, string[]]) =>
clientids.map(clientid => ({clientid, userid})),
);

Expand Down Expand Up @@ -430,19 +466,40 @@ export class CallingRepository {
const currentTimestamp = this.serverTimeHandler.toServerTimestamp();
const toSecond = (timestamp: number) => Math.floor(timestamp / 1000);
const contentStr = JSON.stringify(content);
if (content.type === CALL_MESSAGE_TYPE.GROUP_LEAVE) {
const isAnotherSelfClient = userId === this.selfUser.id && clientId !== this.selfClientId;
if (isAnotherSelfClient) {
const call = this.findCall(conversationId);
if (call?.state() === CALL_STATE.INCOMING) {
// If the group leave was sent from the self user from another device,
// we reset the reason so that the call is not shown in the UI.
// If the call is already accepted, we keep the call UI.
call.reason(REASON.STILL_ONGOING);

let validatedPromise = Promise.resolve('default');
switch (content.type) {
case CALL_MESSAGE_TYPE.GROUP_LEAVE: {
const isAnotherSelfClient = userId === this.selfUser.id && clientId !== this.selfClientId;
if (isAnotherSelfClient) {
const call = this.findCall(conversationId);
if (call?.state() === CALL_STATE.INCOMING) {
// If the group leave was sent from the self user from another device,
// we reset the reason so that the call is not shown in the UI.
// If the call is already accepted, we keep the call UI.
call.reason(REASON.STILL_ONGOING);
}
}
break;
}
case CALL_MESSAGE_TYPE.SETUP:
case CALL_MESSAGE_TYPE.CONF_START:
case CALL_MESSAGE_TYPE.CONFKEY:
case CALL_MESSAGE_TYPE.GROUP_START: {
if (source !== EventRepository.SOURCE.STREAM) {
const recipients = await this.conversationRepository.create_recipients(conversationId, false, [userId]);
const eventInfoEntity = new EventInfoEntity(undefined, conversationId, {recipients});
eventInfoEntity.setType(GENERIC_MESSAGE_TYPE.CALLING);
const consentType = ConversationRepository.CONSENT_TYPE.INCOMING_CALL;
validatedPromise = this.conversationRepository.grantMessage(eventInfoEntity, consentType);
}

break;
}
}

await validatedPromise.catch(() => this.leaveCall(conversationId));

const res = this.wCall.recvMsg(
this.wUser,
contentStr,
Expand Down Expand Up @@ -581,12 +638,6 @@ export class CallingRepository {
async answerCall(call: Call, callType: CALL_TYPE): Promise<void> {
try {
await this.checkConcurrentJoinedCall(call.conversationId, CALL_STATE.INCOMING);
const eventInfoEntity = new EventInfoEntity(undefined, call.conversationId);
eventInfoEntity.setType(GENERIC_MESSAGE_TYPE.CALLING);
await this.conversationRepository.grantMessage(
eventInfoEntity,
ConversationRepository.CONSENT_TYPE.INCOMING_CALL,
);

const isVideoCall = callType === CALL_TYPE.VIDEO;
if (!isVideoCall) {
Expand Down
8 changes: 1 addition & 7 deletions src/script/conversation/ConversationRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -2427,7 +2427,7 @@ export class ConversationRepository {
* @param {Array<string>} user_ids Optionally the intended recipient users
* @returns {Promise<Recipients>} Resolves with a user client map
*/
create_recipients(conversation_id, skip_own_clients = false, user_ids) {
create_recipients(conversation_id, skip_own_clients = false, user_ids = null) {
return this.get_all_users_in_conversation(conversation_id).then(user_ets => {
const recipients = {};

Expand Down Expand Up @@ -2893,18 +2893,12 @@ export class ConversationRepository {

switch (consentType) {
case ConversationRepository.CONSENT_TYPE.INCOMING_CALL: {
if (conversationEntity.hasActiveCall()) {
return resolve(true);
}
actionString = t('modalConversationNewDeviceIncomingCallAction');
messageString = t('modalConversationNewDeviceIncomingCallMessage');
break;
}

case ConversationRepository.CONSENT_TYPE.OUTGOING_CALL: {
if (conversationEntity.hasActiveCall()) {
return resolve(true);
}
actionString = t('modalConversationNewDeviceOutgoingCallAction');
messageString = t('modalConversationNewDeviceOutgoingCallMessage');
break;
Expand Down
4 changes: 2 additions & 2 deletions src/script/conversation/EventInfoEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {Recipients} from '../cryptography/CryptographyRepository';

export interface MessageSendingOptions {
/** Send native push notification for message. Default is `true`. */
nativePush: string[] | boolean;
nativePush?: string[] | boolean;
/**
* Level that backend checks for missing clients. Default is `false`.
*
Expand All @@ -32,7 +32,7 @@ export interface MessageSendingOptions {
* * `Array<string>`: only clients of listed users
* * `true`: force sending
*/
precondition: string[] | boolean;
precondition?: string[] | boolean;
recipients: Recipients;
}

Expand Down
2 changes: 1 addition & 1 deletion src/script/entity/Conversation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -909,7 +909,7 @@ export class Conversation {
return this.getLastMessage()?.timestamp() ? this.getLastMessage().timestamp() >= this.last_event_timestamp() : true;
};

hasActiveCall = (): boolean => [CALL_STATE.INCOMING, CALL_STATE.MEDIA_ESTAB].includes(this.call()?.state());
hasActiveCall = (): boolean => this.call()?.state() === CALL_STATE.MEDIA_ESTAB;

serialize(): SerializedConversation {
return {
Expand Down

0 comments on commit 6f78c91

Please sign in to comment.