Add expire timers to pin/unpin data messages

This commit is contained in:
Jamie
2026-01-14 08:35:24 -08:00
committed by GitHub
parent 3fe00d80ea
commit 040b3fe7b8
14 changed files with 59 additions and 15 deletions

View File

@@ -2495,6 +2495,8 @@ export async function startApp(): Promise<void> {
pinnedByAci: data.sourceAci,
sentAtTimestamp: data.timestamp,
receivedAtTimestamp: data.receivedAtDate,
expireTimer: data.message.expireTimer,
expirationStartTimestamp: null,
});
confirm();
return;
@@ -3003,6 +3005,8 @@ export async function startApp(): Promise<void> {
pinnedByAci: sourceServiceId,
sentAtTimestamp: data.timestamp,
receivedAtTimestamp: data.receivedAtDate,
expireTimer: data.message.expireTimer,
expirationStartTimestamp: data.expirationStartTimestamp ?? null,
});
confirm();
return;

View File

@@ -209,6 +209,7 @@ const pinMessageJobDataSchema = z.object({
targetAuthorAci: aciSchema,
targetSentTimestamp: z.number(),
pinDurationSeconds: z.number().nullable(),
pinnedAt: z.number(),
});
export type PinMessageJobData = z.infer<typeof pinMessageJobDataSchema>;
@@ -290,6 +291,7 @@ const unpinMessageJobDataSchema = z.object({
targetMessageId: z.string(),
targetAuthorAci: aciSchema,
targetSentTimestamp: z.number(),
unpinnedAt: z.number(),
});
export type UnpinMessageJobData = z.infer<typeof unpinMessageJobDataSchema>;

View File

@@ -27,9 +27,9 @@ export type SendMessageJobOptions<Data> = Readonly<{
sendType: SendTypesType;
getMessageId: (data: Data) => string | null;
getMessageOptions: (
data: Data,
jobTimestamp: number
data: Data
) => Omit<SharedMessageOptionsType, 'recipients'>;
getExpirationStartTimestamp: (data: Data) => number | null;
}>;
export function createSendMessageJob<Data>(
@@ -40,7 +40,13 @@ export function createSendMessageJob<Data>(
job: ConversationQueueJobBundle,
data: Data
): Promise<void> {
const { sendName, sendType, getMessageId, getMessageOptions } = options;
const {
sendName,
sendType,
getMessageId,
getMessageOptions,
getExpirationStartTimestamp,
} = options;
const logId = `${sendName}(${conversation.idForLogging()}/${job.timestamp})`;
const log = job.log.child(logId);
@@ -71,7 +77,12 @@ export function createSendMessageJob<Data>(
}
const messageId = getMessageId(data);
const messageOptions = getMessageOptions(data, job.timestamp);
const messageOptions = {
...getMessageOptions(data),
expireTimer: conversation.get('expireTimer'),
expireTimerVersion: conversation.getExpireTimerVersion(),
};
const expirationStartTimestamp = getExpirationStartTimestamp(data);
try {
if (recipientServiceIdsWithoutMe.length === 0) {
@@ -96,7 +107,7 @@ export function createSendMessageJob<Data>(
timestamp: job.timestamp,
destinationE164: conversation.get('e164'),
destinationServiceId: conversation.getServiceId(),
expirationStartTimestamp: null,
expirationStartTimestamp,
isUpdate: false,
options: sendOptions,
urgent: false,
@@ -128,7 +139,7 @@ export function createSendMessageJob<Data>(
send: sender => {
return sender.sendMessageToServiceId({
serviceId: recipientServiceId,
messageOptions: getMessageOptions(data, job.timestamp),
messageOptions,
groupId: undefined,
contentHint: ContentHint.Resendable,
options: sendOptions,
@@ -138,6 +149,7 @@ export function createSendMessageJob<Data>(
},
sendType,
timestamp: job.timestamp,
expirationStartTimestamp,
});
}
);
@@ -162,8 +174,8 @@ export function createSendMessageJob<Data>(
abortSignal,
contentHint: ContentHint.Resendable,
groupSendOptions: {
...messageOptions,
groupV2: groupV2Info,
...getMessageOptions(data, job.timestamp),
},
messageId: messageId ?? undefined,
sendOptions,
@@ -174,6 +186,7 @@ export function createSendMessageJob<Data>(
},
sendType,
timestamp: job.timestamp,
expirationStartTimestamp,
});
}
);

View File

@@ -213,6 +213,7 @@ export async function sendDeleteForEveryone(
}),
sendType,
timestamp,
expirationStartTimestamp: null,
});
await updateMessageWithSuccessfulSends(message);
@@ -252,6 +253,7 @@ export async function sendDeleteForEveryone(
}),
sendType,
timestamp,
expirationStartTimestamp: null,
});
await updateMessageWithSuccessfulSends(message);

View File

@@ -153,6 +153,7 @@ export async function sendDirectExpirationTimerUpdate(
}),
sendType,
timestamp,
expirationStartTimestamp: null,
});
}
} catch (error: unknown) {

View File

@@ -97,6 +97,7 @@ export async function sendGroupCallUpdate(
),
sendType,
timestamp,
expirationStartTimestamp: null,
});
} catch (error: unknown) {
await handleMultipleSendErrors({

View File

@@ -117,6 +117,7 @@ export async function sendGroupUpdate(
}),
sendType,
timestamp,
expirationStartTimestamp: null,
})
);
} catch (error: unknown) {

View File

@@ -9,9 +9,9 @@ export const sendPinMessage = createSendMessageJob<PinMessageJobData>({
getMessageId(data) {
return data.targetMessageId;
},
getMessageOptions(data, jobTimestamp) {
getMessageOptions(data) {
return {
timestamp: jobTimestamp,
timestamp: data.pinnedAt,
pinMessage: {
targetAuthorAci: data.targetAuthorAci,
targetSentTimestamp: data.targetSentTimestamp,
@@ -19,4 +19,7 @@ export const sendPinMessage = createSendMessageJob<PinMessageJobData>({
},
};
},
getExpirationStartTimestamp(data) {
return data.pinnedAt;
},
});

View File

@@ -133,6 +133,7 @@ export async function sendPollTerminate(
}),
sendType: 'pollTerminate',
timestamp,
expirationStartTimestamp: null,
});
await markTerminateSuccess(pollMessage, jobLog);

View File

@@ -10,13 +10,16 @@ export const sendUnpinMessage = createSendMessageJob<UnpinMessageJobData>({
getMessageId(data) {
return data.targetMessageId;
},
getMessageOptions(data, jobTimestamp) {
getMessageOptions(data) {
return {
timestamp: jobTimestamp,
timestamp: data.unpinnedAt,
unpinMessage: {
targetAuthorAci: data.targetAuthorAci,
targetSentTimestamp: data.targetSentTimestamp,
},
};
},
getExpirationStartTimestamp(data) {
return data.unpinnedAt;
},
});

View File

@@ -30,6 +30,8 @@ export type PinnedMessageAddProps = Readonly<{
pinnedByAci: AciString;
sentAtTimestamp: number;
receivedAtTimestamp: number;
expireTimer: DurationInSeconds | null;
expirationStartTimestamp: number | null;
}>;
export type PinnedMessageRemoveProps = Readonly<{
@@ -125,6 +127,8 @@ export async function onPinnedMessageAdd(
senderAci: props.pinnedByAci,
sentAtTimestamp: props.sentAtTimestamp,
receivedAtTimestamp: props.receivedAtTimestamp,
expireTimer: props.expireTimer,
expirationStartTimestamp: props.expirationStartTimestamp,
});
}

View File

@@ -3567,6 +3567,8 @@ export class ConversationModel {
senderAci: AciString;
sentAtTimestamp: number;
receivedAtTimestamp: number;
expireTimer: DurationInSeconds | null;
expirationStartTimestamp: number | null;
}): Promise<void> {
const ourAci = itemStorage.user.getCheckedAci();
const senderIsMe = params.senderAci === ourAci;
@@ -3581,8 +3583,8 @@ export class ConversationModel {
readStatus: senderIsMe ? ReadStatus.Read : ReadStatus.Unread,
seenStatus: senderIsMe ? SeenStatus.Seen : SeenStatus.Unseen,
sourceServiceId: params.senderAci,
expireTimer: this.get('expireTimer'),
expirationStartTimestamp: senderIsMe ? params.sentAtTimestamp : null,
expireTimer: params.expireTimer ?? undefined,
expirationStartTimestamp: params.expirationStartTimestamp,
pinMessage: params.pinMessage,
});

View File

@@ -5199,15 +5199,17 @@ function onPinnedMessageAdd(
);
strictAssert(targetConversation != null, 'Missing target conversation');
const pinnedAt = Date.now();
await conversationJobQueue.add({
type: conversationQueueJobEnum.enum.PinMessage,
...target,
pinDurationSeconds,
pinnedAt,
});
const pinnedMessagesLimit = getPinnedMessagesLimit();
const pinnedAt = Date.now();
const expiresAt = getPinnedMessageExpiresAt(pinnedAt, pinDurationSeconds);
await DataWriter.appendPinnedMessage(pinnedMessagesLimit, {
@@ -5226,6 +5228,8 @@ function onPinnedMessageAdd(
senderAci: itemStorage.user.getCheckedAci(),
sentAtTimestamp: pinnedAt,
receivedAtTimestamp: pinnedAt,
expireTimer: targetConversation.get('expireTimer') ?? null,
expirationStartTimestamp: pinnedAt,
});
dispatch(onPinnedMessagesChanged(target.conversationId));
@@ -5238,6 +5242,7 @@ function onPinnedMessageRemove(targetMessageId: string): StateThunk {
await conversationJobQueue.add({
type: conversationQueueJobEnum.enum.UnpinMessage,
...target,
unpinnedAt: Date.now(),
});
await DataWriter.deletePinnedMessageByMessageId(targetMessageId);
drop(pinnedMessagesCleanupService.trigger('onPinnedMessageRemove'));

View File

@@ -25,6 +25,7 @@ export async function wrapWithSyncMessageSend({
send,
sendType,
timestamp,
expirationStartTimestamp,
}: {
conversation: ConversationModel;
logId: string;
@@ -32,6 +33,7 @@ export async function wrapWithSyncMessageSend({
send: (sender: MessageSender) => Promise<CallbackResultType>;
sendType: SendTypesType;
timestamp: number;
expirationStartTimestamp: number | null;
}): Promise<void> {
const logId = `wrapWithSyncMessageSend(${parentLogId}, ${timestamp})`;
@@ -84,7 +86,7 @@ export async function wrapWithSyncMessageSend({
destinationE164: conversation.get('e164'),
destinationServiceId: conversation.getServiceId(),
encodedDataMessage: dataMessage,
expirationStartTimestamp: null,
expirationStartTimestamp,
options,
timestamp,
urgent: false,