contactSync should depend on syncMessage.complete
This commit is contained in:
parent
299044f89f
commit
c42df6312e
3 changed files with 46 additions and 29 deletions
|
@ -13,6 +13,7 @@ import type { ConversationModel } from '../models/conversations';
|
||||||
import { validateConversation } from '../util/validateConversation';
|
import { validateConversation } from '../util/validateConversation';
|
||||||
import { strictAssert } from '../util/assert';
|
import { strictAssert } from '../util/assert';
|
||||||
import { isDirectConversation, isMe } from '../util/whatTypeOfConversation';
|
import { isDirectConversation, isMe } from '../util/whatTypeOfConversation';
|
||||||
|
import { normalizeUuid } from '../util/normalizeUuid';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
|
|
||||||
// When true - we are running the very first storage and contact sync after
|
// When true - we are running the very first storage and contact sync after
|
||||||
|
@ -78,11 +79,24 @@ const queue = new PQueue({ concurrency: 1 });
|
||||||
|
|
||||||
async function doContactSync({
|
async function doContactSync({
|
||||||
contacts,
|
contacts,
|
||||||
|
complete,
|
||||||
receivedAtCounter,
|
receivedAtCounter,
|
||||||
}: ContactSyncEvent): Promise<void> {
|
}: ContactSyncEvent): Promise<void> {
|
||||||
log.info(
|
// iOS sets `syncMessage.contacts.complete` flag to `true` unconditionally
|
||||||
`doContactSync(${receivedAtCounter}): got ${contacts.length} contacts`
|
// and so we have to employ tricks to figure out whether the sync is full or
|
||||||
);
|
// partial. Thankfully, iOS sends only two kinds of contact syncs: full or
|
||||||
|
// local sync. Local sync is always a single our own contact so we can do an
|
||||||
|
// UUID check.
|
||||||
|
const isFullSync =
|
||||||
|
complete &&
|
||||||
|
!(
|
||||||
|
contacts.length === 1 &&
|
||||||
|
normalizeUuid(contacts[0].uuid, 'doContactSync') ===
|
||||||
|
window.storage.user.getUuid()?.toString()
|
||||||
|
);
|
||||||
|
|
||||||
|
const logId = `doContactSync(${receivedAtCounter}, isFullSync=${isFullSync})`;
|
||||||
|
log.info(`${logId}: got ${contacts.length} contacts`);
|
||||||
|
|
||||||
const updatedConversations = new Set<ConversationModel>();
|
const updatedConversations = new Set<ConversationModel>();
|
||||||
|
|
||||||
|
@ -97,7 +111,7 @@ async function doContactSync({
|
||||||
const validationError = validateConversation(partialConversation);
|
const validationError = validateConversation(partialConversation);
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
log.error(
|
log.error(
|
||||||
`doContactSync(${receivedAtCounter}): Invalid contact received`,
|
`${logId}: Invalid contact received`,
|
||||||
Errors.toLogFormat(validationError)
|
Errors.toLogFormat(validationError)
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
|
@ -106,32 +120,29 @@ async function doContactSync({
|
||||||
const conversation = window.ConversationController.maybeMergeContacts({
|
const conversation = window.ConversationController.maybeMergeContacts({
|
||||||
e164: details.number,
|
e164: details.number,
|
||||||
aci: details.uuid,
|
aci: details.uuid,
|
||||||
reason: `doContactSync(${receivedAtCounter})`,
|
reason: logId,
|
||||||
});
|
});
|
||||||
strictAssert(conversation, 'need conversation to queue the job!');
|
strictAssert(conversation, 'need conversation to queue the job!');
|
||||||
|
|
||||||
// It's important to use queueJob here because we might update the expiration timer
|
// It's important to use queueJob here because we might update the expiration timer
|
||||||
// and we don't want conflicts with incoming message processing happening on the
|
// and we don't want conflicts with incoming message processing happening on the
|
||||||
// conversation queue.
|
// conversation queue.
|
||||||
const job = conversation.queueJob(
|
const job = conversation.queueJob(`${logId}.set`, async () => {
|
||||||
`doContactSync(${receivedAtCounter}).set`,
|
try {
|
||||||
async () => {
|
await updateConversationFromContactSync(
|
||||||
try {
|
conversation,
|
||||||
await updateConversationFromContactSync(
|
details,
|
||||||
conversation,
|
receivedAtCounter
|
||||||
details,
|
);
|
||||||
receivedAtCounter
|
|
||||||
);
|
|
||||||
|
|
||||||
updatedConversations.add(conversation);
|
updatedConversations.add(conversation);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
log.error(
|
log.error(
|
||||||
'updateConversationFromContactSync error:',
|
'updateConversationFromContactSync error:',
|
||||||
Errors.toLogFormat(error)
|
Errors.toLogFormat(error)
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
|
|
||||||
promises.push(job);
|
promises.push(job);
|
||||||
}
|
}
|
||||||
|
@ -140,15 +151,19 @@ async function doContactSync({
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
promises = [];
|
promises = [];
|
||||||
|
|
||||||
const notUpdated = window.ConversationController.getAll().filter(
|
// Erase data in conversations that are not the part of contact sync only
|
||||||
convo =>
|
// if we received a full contact sync (and not a one-off contact update).
|
||||||
!updatedConversations.has(convo) &&
|
const notUpdated = isFullSync
|
||||||
isDirectConversation(convo.attributes) &&
|
? window.ConversationController.getAll().filter(
|
||||||
!isMe(convo.attributes)
|
convo =>
|
||||||
);
|
!updatedConversations.has(convo) &&
|
||||||
|
isDirectConversation(convo.attributes) &&
|
||||||
|
!isMe(convo.attributes)
|
||||||
|
)
|
||||||
|
: [];
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
`doContactSync(${receivedAtCounter}): ` +
|
`${logId}: ` +
|
||||||
`updated ${updatedConversations.size} ` +
|
`updated ${updatedConversations.size} ` +
|
||||||
`resetting ${notUpdated.length}`
|
`resetting ${notUpdated.length}`
|
||||||
);
|
);
|
||||||
|
|
|
@ -3070,6 +3070,7 @@ export default class MessageReceiver
|
||||||
|
|
||||||
const contactSync = new ContactSyncEvent(
|
const contactSync = new ContactSyncEvent(
|
||||||
Array.from(contactBuffer),
|
Array.from(contactBuffer),
|
||||||
|
Boolean(contacts.complete),
|
||||||
envelope.receivedAtCounter
|
envelope.receivedAtCounter
|
||||||
);
|
);
|
||||||
await this.dispatchAndWait(contactSync);
|
await this.dispatchAndWait(contactSync);
|
||||||
|
|
|
@ -76,6 +76,7 @@ export class ErrorEvent extends Event {
|
||||||
export class ContactSyncEvent extends Event {
|
export class ContactSyncEvent extends Event {
|
||||||
constructor(
|
constructor(
|
||||||
public readonly contacts: ReadonlyArray<ModifiedContactDetails>,
|
public readonly contacts: ReadonlyArray<ModifiedContactDetails>,
|
||||||
|
public readonly complete: boolean,
|
||||||
public readonly receivedAtCounter: number
|
public readonly receivedAtCounter: number
|
||||||
) {
|
) {
|
||||||
super('contactSync');
|
super('contactSync');
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue