diff --git a/ts/groups.ts b/ts/groups.ts index 7f578ca292..e5ac5f6829 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 9fa6c9771a..f0a13c740d 100644 --- a/ts/models/conversations.ts +++ b/ts/models/conversations.ts @@ -216,6 +216,8 @@ export class ConversationModel extends window.Backbone // This number is recorded as an optimization and may be out of date. private newestReceivedAtMarkedRead?: number; + private _activeProfileFetch?: Promise; + override defaults(): Partial { return { unreadCount: 0, @@ -4648,12 +4650,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 {