Refactor target message for delivery receipt processing
This commit is contained in:
parent
e724f36b79
commit
c2b1d76e6d
3 changed files with 82 additions and 40 deletions
|
@ -15,6 +15,7 @@ import * as Errors from '../types/errors';
|
||||||
import {
|
import {
|
||||||
SendActionType,
|
SendActionType,
|
||||||
SendStatus,
|
SendStatus,
|
||||||
|
UNDELIVERED_SEND_STATUSES,
|
||||||
sendStateReducer,
|
sendStateReducer,
|
||||||
} from '../messages/MessageSendState';
|
} from '../messages/MessageSendState';
|
||||||
import type { DeleteSentProtoRecipientOptionsType } from '../sql/Interface';
|
import type { DeleteSentProtoRecipientOptionsType } from '../sql/Interface';
|
||||||
|
@ -25,6 +26,7 @@ import { queueUpdateMessage } from '../util/messageBatcher';
|
||||||
import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp';
|
import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp';
|
||||||
import { getMessageIdForLogging } from '../util/idForLogging';
|
import { getMessageIdForLogging } from '../util/idForLogging';
|
||||||
import { generateCacheKey } from './generateCacheKey';
|
import { generateCacheKey } from './generateCacheKey';
|
||||||
|
import { getPropForTimestamp } from '../util/editHelpers';
|
||||||
|
|
||||||
const { deleteSentProtoRecipient } = dataInterface;
|
const { deleteSentProtoRecipient } = dataInterface;
|
||||||
|
|
||||||
|
@ -38,7 +40,7 @@ export type MessageReceiptAttributesType = {
|
||||||
envelopeId: string;
|
envelopeId: string;
|
||||||
messageSentAt: number;
|
messageSentAt: number;
|
||||||
receiptTimestamp: number;
|
receiptTimestamp: number;
|
||||||
removeFromMessageReceiverCache: () => unknown;
|
removeFromMessageReceiverCache: () => void;
|
||||||
sourceConversationId: string;
|
sourceConversationId: string;
|
||||||
sourceDevice: number;
|
sourceDevice: number;
|
||||||
sourceServiceId: ServiceIdString;
|
sourceServiceId: ServiceIdString;
|
||||||
|
@ -89,45 +91,74 @@ function remove(receipt: MessageReceiptAttributesType): void {
|
||||||
receipt.removeFromMessageReceiverCache();
|
receipt.removeFromMessageReceiverCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTargetMessage(
|
function getTargetMessage({
|
||||||
sourceId: string,
|
sourceConversationId,
|
||||||
serviceId: ServiceIdString,
|
messages,
|
||||||
messages: ReadonlyArray<MessageAttributesType>
|
targetTimestamp,
|
||||||
): Promise<MessageModel | null> {
|
}: {
|
||||||
|
sourceConversationId: string;
|
||||||
|
messages: ReadonlyArray<MessageAttributesType>;
|
||||||
|
targetTimestamp: number;
|
||||||
|
}): MessageModel | null {
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const message = messages.find(
|
|
||||||
item =>
|
|
||||||
(isOutgoing(item) || isStory(item)) && sourceId === item.conversationId
|
|
||||||
);
|
|
||||||
if (message) {
|
|
||||||
return window.MessageCache.__DEPRECATED$register(
|
|
||||||
message.id,
|
|
||||||
message,
|
|
||||||
'MessageReceipts.getTargetMessage 1'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const groups = await window.Signal.Data.getAllGroupsInvolvingServiceId(
|
const matchingMessages = messages
|
||||||
serviceId
|
.filter(msg => isOutgoing(msg) || isStory(msg))
|
||||||
);
|
.filter(msg => {
|
||||||
|
const sendStateByConversationId = getPropForTimestamp({
|
||||||
|
message: msg,
|
||||||
|
prop: 'sendStateByConversationId',
|
||||||
|
targetTimestamp,
|
||||||
|
log,
|
||||||
|
});
|
||||||
|
|
||||||
const ids = groups.map(item => item.id);
|
const isRecipient = Object.hasOwn(
|
||||||
ids.push(sourceId);
|
sendStateByConversationId ?? {},
|
||||||
|
sourceConversationId
|
||||||
|
);
|
||||||
|
if (!isRecipient) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const target = messages.find(
|
const sendStatus =
|
||||||
item =>
|
sendStateByConversationId?.[sourceConversationId]?.status;
|
||||||
(isOutgoing(item) || isStory(item)) && ids.includes(item.conversationId)
|
|
||||||
);
|
if (
|
||||||
if (!target) {
|
sendStatus === undefined ||
|
||||||
|
UNDELIVERED_SEND_STATUSES.includes(sendStatus)
|
||||||
|
) {
|
||||||
|
log.warn(`
|
||||||
|
MessageReceipts.getTargetMessage: received receipt for undelivered message,
|
||||||
|
status: ${sendStatus},
|
||||||
|
sourceConversationId: ${sourceConversationId},
|
||||||
|
message: ${getMessageIdForLogging(message)}.
|
||||||
|
`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (matchingMessages.length === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (matchingMessages.length > 1) {
|
||||||
|
log.warn(`
|
||||||
|
MessageReceipts.getTargetMessage: multiple (${matchingMessages.length})
|
||||||
|
matching messages for receipt,
|
||||||
|
sentAt=${targetTimestamp},
|
||||||
|
sourceConversationId=${sourceConversationId}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const message = matchingMessages[0];
|
||||||
return window.MessageCache.__DEPRECATED$register(
|
return window.MessageCache.__DEPRECATED$register(
|
||||||
target.id,
|
message.id,
|
||||||
target,
|
message,
|
||||||
'MessageReceipts.getTargetMessage 2'
|
'MessageReceipts.getTargetMessage'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,11 +398,11 @@ export async function onReceipt(
|
||||||
messageSentAt
|
messageSentAt
|
||||||
);
|
);
|
||||||
|
|
||||||
const message = await getTargetMessage(
|
const message = getTargetMessage({
|
||||||
sourceConversationId,
|
sourceConversationId,
|
||||||
sourceServiceId,
|
messages,
|
||||||
messages
|
targetTimestamp: receipt.messageSentAt,
|
||||||
);
|
});
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
await updateMessageSendState(receipt, message);
|
await updateMessageSendState(receipt, message);
|
||||||
|
|
|
@ -39,6 +39,11 @@ export const parseMessageSendStatus = makeEnumParser(
|
||||||
SendStatus.Pending
|
SendStatus.Pending
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const UNDELIVERED_SEND_STATUSES = [
|
||||||
|
SendStatus.Pending,
|
||||||
|
SendStatus.Failed,
|
||||||
|
];
|
||||||
|
|
||||||
const STATUS_NUMBERS: Record<SendStatus, number> = {
|
const STATUS_NUMBERS: Record<SendStatus, number> = {
|
||||||
[SendStatus.Failed]: 0,
|
[SendStatus.Failed]: 0,
|
||||||
[SendStatus.Pending]: 1,
|
[SendStatus.Pending]: 1,
|
||||||
|
|
|
@ -5,9 +5,10 @@ import { isNumber, sortBy } from 'lodash';
|
||||||
|
|
||||||
import { strictAssert } from './assert';
|
import { strictAssert } from './assert';
|
||||||
|
|
||||||
import type { EditHistoryType } from '../model-types';
|
import type { EditHistoryType, MessageAttributesType } from '../model-types';
|
||||||
import type { MessageModel } from '../models/messages';
|
|
||||||
import type { LoggerType } from '../types/Logging';
|
import type { LoggerType } from '../types/Logging';
|
||||||
|
import { getMessageIdForLogging } from './idForLogging';
|
||||||
|
import type { MessageModel } from '../models/messages';
|
||||||
|
|
||||||
// The tricky bit for this function is if we are on our second+ attempt to send a given
|
// The tricky bit for this function is if we are on our second+ attempt to send a given
|
||||||
// edit, we're still sending that edit.
|
// edit, we're still sending that edit.
|
||||||
|
@ -51,13 +52,18 @@ export function getPropForTimestamp<T extends keyof EditHistoryType>({
|
||||||
targetTimestamp,
|
targetTimestamp,
|
||||||
}: {
|
}: {
|
||||||
log: LoggerType;
|
log: LoggerType;
|
||||||
message: MessageModel;
|
message: MessageModel | MessageAttributesType;
|
||||||
prop: T;
|
prop: T;
|
||||||
targetTimestamp: number;
|
targetTimestamp: number;
|
||||||
}): EditHistoryType[T] {
|
}): EditHistoryType[T] {
|
||||||
const logId = `getPropForTimestamp(${message.idForLogging()}, target=${targetTimestamp}})`;
|
const attributes =
|
||||||
|
message instanceof window.Whisper.Message ? message.attributes : message;
|
||||||
|
|
||||||
const editHistory = message.get('editHistory');
|
const logId = `getPropForTimestamp(${getMessageIdForLogging(
|
||||||
|
attributes
|
||||||
|
)}, target=${targetTimestamp}})`;
|
||||||
|
|
||||||
|
const { editHistory } = attributes;
|
||||||
const targetEdit = editHistory?.find(
|
const targetEdit = editHistory?.find(
|
||||||
item => item.timestamp === targetTimestamp
|
item => item.timestamp === targetTimestamp
|
||||||
);
|
);
|
||||||
|
@ -65,7 +71,7 @@ export function getPropForTimestamp<T extends keyof EditHistoryType>({
|
||||||
if (editHistory) {
|
if (editHistory) {
|
||||||
log.warn(`${logId}: No edit found, using top-level data`);
|
log.warn(`${logId}: No edit found, using top-level data`);
|
||||||
}
|
}
|
||||||
return message.get(prop);
|
return attributes[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
return targetEdit[prop];
|
return targetEdit[prop];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue