From 54136ecc317c3f0b2cf367f9fd0a9324c8018da6 Mon Sep 17 00:00:00 2001 From: Fedor Indutny <79877362+indutny-signal@users.noreply.github.com> Date: Thu, 27 Jan 2022 16:35:11 -0800 Subject: [PATCH] Create contacts during processing of group updates --- ts/groups.ts | 44 ++++++++++++++++++++++++++++++-------- ts/models/conversations.ts | 31 +++++++++++++++++++++------ 2 files changed, 60 insertions(+), 15 deletions(-) diff --git a/ts/groups.ts b/ts/groups.ts index 0c07114ec..fbfc33bb9 100644 --- a/ts/groups.ts +++ b/ts/groups.ts @@ -12,6 +12,7 @@ import { import type { ClientZkGroupCipher } from '@signalapp/signal-client/zkgroup'; import { v4 as getGuid } from 'uuid'; import LRU from 'lru-cache'; +import PQueue from 'p-queue'; import * as log from './logging/log'; import { getCredentialsForToday, @@ -2794,6 +2795,8 @@ async function updateGroup( }, { viaSync = false } = {} ): Promise { + const logId = conversation.idForLogging(); + const { newAttributes, groupChangeMessages, members } = updates; const ourUuid = window.textsecure.storage.user.getCheckedUuid(); @@ -2859,6 +2862,38 @@ async function updateGroup( }; }); + const contactsWithoutProfileKey = new Array(); + + // Capture profile key for each member in the group, if we don't have it yet + members.forEach(member => { + const contact = window.ConversationController.getOrCreate( + member.uuid, + 'private' + ); + + if (member.profileKey && !contact.get('profileKey')) { + contactsWithoutProfileKey.push(contact); + contact.setProfileKey(member.profileKey); + } + }); + + if (contactsWithoutProfileKey.length !== 0) { + log.info( + `updateGroup/${logId}: fetching ` + + `${contactsWithoutProfileKey.length} missing profiles` + ); + + const profileFetchQueue = new PQueue({ + concurrency: 3, + }); + await profileFetchQueue.addAll( + contactsWithoutProfileKey.map(contact => () => { + const active = contact.getActiveProfileFetch(); + return active || contact.getProfiles(); + }) + ); + } + if (changeMessagesToSave.length > 0) { await window.Signal.Data.saveMessages(changeMessagesToSave, { forceSave: true, @@ -2871,15 +2906,6 @@ async function updateGroup( }); } - // Capture profile key for each member in the group, if we don't have it yet - members.forEach(member => { - const contact = window.ConversationController.get(member.uuid); - - if (member.profileKey && contact && !contact.get('profileKey')) { - contact.setProfileKey(member.profileKey); - } - }); - // No need for convo.updateLastMessage(), 'newmessage' handler does that } diff --git a/ts/models/conversations.ts b/ts/models/conversations.ts index 8de238173..3a52c4a7f 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -213,6 +213,8 @@ export class ConversationModel extends window.Backbone private isInReduxBatch = false; + private _activeProfileFetch?: Promise; + override defaults(): Partial { return { unreadCount: 0, @@ -4634,12 +4636,29 @@ export class ConversationModel extends window.Backbone const queue = new PQueue({ concurrency: 3, }); - await queue.addAll( - conversations.map( - conversation => () => - getProfile(conversation.get('uuid'), conversation.get('e164')) - ) - ); + + // Convert Promise that is returned by addAll() to Promise + const promise = (async () => { + await queue.addAll( + conversations.map( + conversation => () => + getProfile(conversation.get('uuid'), conversation.get('e164')) + ) + ); + })(); + + this._activeProfileFetch = promise; + try { + await promise; + } finally { + if (this._activeProfileFetch === promise) { + this._activeProfileFetch = undefined; + } + } + } + + getActiveProfileFetch(): Promise | undefined { + return this._activeProfileFetch; } async setEncryptedProfileName(encryptedName: string): Promise {