Use minimal replacement class for MessageModel

This commit is contained in:
Scott Nonnenberg
2025-01-10 08:18:32 +10:00
committed by GitHub
parent 6b00cf756e
commit f846678b90
95 changed files with 3919 additions and 4457 deletions

View File

@@ -126,11 +126,12 @@ import {
isDirectConversation,
isGroup,
isGroupV2,
isMe,
} from '../../util/whatTypeOfConversation';
import { missingCaseError } from '../../util/missingCaseError';
import { viewSyncJobQueue } from '../../jobs/viewSyncJobQueue';
import { ReadStatus } from '../../messages/MessageReadStatus';
import { isIncoming, processBodyRanges } from '../selectors/message';
import { isIncoming, isStory, processBodyRanges } from '../selectors/message';
import { getActiveCall, getActiveCallState } from '../selectors/calling';
import { sendDeleteForEveryoneMessage } from '../../util/sendDeleteForEveryoneMessage';
import type { ShowToastActionType } from './toast';
@@ -149,7 +150,7 @@ import {
buildUpdateAttributesChange,
initiateMigrationToGroupV2 as doInitiateMigrationToGroupV2,
} from '../../groups';
import { __DEPRECATED$getMessageById } from '../../messages/getMessageById';
import { getMessageById } from '../../messages/getMessageById';
import type { PanelRenderType, PanelRequestType } from '../../types/Panels';
import type { ConversationQueueJobData } from '../../jobs/conversationJobQueue';
import { isOlderThan } from '../../util/timestamp';
@@ -184,7 +185,10 @@ import type { ChangeNavTabActionType } from './nav';
import { CHANGE_NAV_TAB, NavTab, actions as navActions } from './nav';
import { sortByMessageOrder } from '../../types/ForwardDraft';
import { getAddedByForOurPendingInvitation } from '../../util/getAddedByForOurPendingInvitation';
import { getConversationIdForLogging } from '../../util/idForLogging';
import {
getConversationIdForLogging,
getMessageIdForLogging,
} from '../../util/idForLogging';
import { singleProtoJobQueue } from '../../jobs/singleProtoJobQueue';
import MessageSender from '../../textsecure/SendMessage';
import {
@@ -204,6 +208,18 @@ import { markCallHistoryReadInConversation } from './callHistory';
import type { CapabilitiesType } from '../../textsecure/WebAPI';
import { actions as searchActions } from './search';
import type { SearchActionType } from './search';
import { getNotificationTextForMessage } from '../../util/getNotificationTextForMessage';
import { doubleCheckMissingQuoteReference as doDoubleCheckMissingQuoteReference } from '../../util/doubleCheckMissingQuoteReference';
import { queueAttachmentDownloadsForMessage } from '../../util/queueAttachmentDownloads';
import { markAttachmentAsCorrupted as doMarkAttachmentAsCorrupted } from '../../messageModifiers/AttachmentDownloads';
import {
isSent,
SendActionType,
sendStateReducer,
} from '../../messages/MessageSendState';
import { markFailed } from '../../test-node/util/messageFailures';
import { cleanupMessages, postSaveUpdates } from '../../util/cleanup';
import { MessageModel } from '../../models/messages';
// State
export type DBConversationType = ReadonlyDeep<{
@@ -1410,10 +1426,7 @@ function markMessageRead(
return;
}
const message = await __DEPRECATED$getMessageById(
messageId,
'markMessageRead'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`markMessageRead: failed to load message ${messageId}`);
}
@@ -1767,10 +1780,7 @@ function deleteMessages({
await Promise.all(
messageIds.map(
async (messageId): Promise<MessageToDelete | undefined> => {
const message = await __DEPRECATED$getMessageById(
messageId,
'deleteMessages'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`deleteMessages: Message ${messageId} missing!`);
}
@@ -1805,7 +1815,7 @@ function deleteMessages({
}
await DataWriter.removeMessages(messageIds, {
singleProtoJobQueue,
cleanupMessages,
});
popPanelForConversation()(dispatch, getState, undefined);
@@ -1930,9 +1940,7 @@ function setMessageToEdit(
return;
}
const message = (
await __DEPRECATED$getMessageById(messageId, 'setMessageToEdit')
)?.attributes;
const message = (await getMessageById(messageId))?.attributes;
if (!message) {
return;
}
@@ -2025,10 +2033,7 @@ function generateNewGroupLink(
* replace it with an actual action that fits in with the redux approach.
*/
export const markViewed = (messageId: string): void => {
const message = window.MessageCache.__DEPRECATED$getById(
messageId,
'markViewed'
);
const message = window.MessageCache.getById(messageId);
if (!message) {
throw new Error(`markViewed: Message ${messageId} missing!`);
}
@@ -2051,7 +2056,9 @@ export const markViewed = (messageId: string): void => {
);
senderAci = sourceServiceId;
const convoAttributes = message.getConversation()?.attributes;
const convo = window.ConversationController.get(
message.get('conversationId')
);
const conversationId = message.get('conversationId');
drop(
conversationJobQueue.add({
@@ -2065,8 +2072,8 @@ export const markViewed = (messageId: string): void => {
senderE164,
senderAci,
timestamp,
isDirectConversation: convoAttributes
? isDirectConversation(convoAttributes)
isDirectConversation: convo
? isDirectConversation(convo.attributes)
: true,
},
],
@@ -2292,16 +2299,14 @@ function kickOffAttachmentDownload(
options: Readonly<{ messageId: string }>
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
options.messageId,
'kickOffAttachmentDownload'
);
const message = await getMessageById(options.messageId);
if (!message) {
throw new Error(
`kickOffAttachmentDownload: Message ${options.messageId} missing!`
);
}
const didUpdateValues = await message.queueAttachmentDownloads(
const didUpdateValues = await queueAttachmentDownloadsForMessage(
message,
AttachmentDownloadUrgency.IMMEDIATE
);
@@ -2309,6 +2314,7 @@ function kickOffAttachmentDownload(
drop(
DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
postSaveUpdates,
})
);
}
@@ -2329,10 +2335,7 @@ function cancelAttachmentDownload({
NoopActionType
> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
messageId,
'cancelAttachmentDownload'
);
const message = await getMessageById(messageId);
if (!message) {
log.warn(`cancelAttachmentDownload: Message ${messageId} missing!`);
} else {
@@ -2344,7 +2347,10 @@ function cancelAttachmentDownload({
});
const ourAci = window.textsecure.storage.user.getCheckedAci();
await DataWriter.saveMessage(message.attributes, { ourAci });
await DataWriter.saveMessage(message.attributes, {
ourAci,
postSaveUpdates,
});
}
// A click kicks off downloads for every attachment in a message, so cancel does too
@@ -2370,16 +2376,7 @@ function markAttachmentAsCorrupted(
options: AttachmentOptions
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
options.messageId,
'markAttachmentAsCorrupted'
);
if (!message) {
throw new Error(
`markAttachmentAsCorrupted: Message ${options.messageId} missing!`
);
}
message.markAttachmentAsCorrupted(options.attachment);
await doMarkAttachmentAsCorrupted(options.messageId, options.attachment);
dispatch({
type: 'NOOP',
@@ -2392,10 +2389,7 @@ function openGiftBadge(
messageId: string
): ThunkAction<void, RootStateType, unknown, ShowToastActionType> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
messageId,
'openGiftBadge'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`openGiftBadge: Message ${messageId} missing!`);
}
@@ -2415,14 +2409,106 @@ function retryMessageSend(
messageId: string
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
messageId,
'retryMessageSend'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`retryMessageSend: Message ${messageId} missing!`);
}
await message.retrySend();
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const conversation = window.ConversationController.get(
message.attributes.conversationId
)!;
let currentConversationRecipients: Set<string> | undefined;
const { storyDistributionListId } = message.attributes;
if (storyDistributionListId) {
const storyDistribution =
await DataReader.getStoryDistributionWithMembers(
storyDistributionListId
);
if (!storyDistribution) {
markFailed(message);
return;
}
currentConversationRecipients = new Set(
storyDistribution.members
.map(serviceId => window.ConversationController.get(serviceId)?.id)
.filter(isNotNil)
);
} else {
currentConversationRecipients = conversation.getMemberConversationIds();
}
// Determine retry recipients and get their most up-to-date addressing information
const oldSendStateByConversationId =
message.get('sendStateByConversationId') || {};
const newSendStateByConversationId = { ...oldSendStateByConversationId };
for (const [conversationId, sendState] of Object.entries(
oldSendStateByConversationId
)) {
if (isSent(sendState.status)) {
continue;
}
const recipient = window.ConversationController.get(conversationId);
if (
!recipient ||
(!currentConversationRecipients.has(conversationId) &&
!isMe(recipient.attributes))
) {
continue;
}
newSendStateByConversationId[conversationId] = sendStateReducer(
sendState,
{
type: SendActionType.ManuallyRetried,
updatedAt: Date.now(),
}
);
}
message.set({ sendStateByConversationId: newSendStateByConversationId });
if (isStory(message.attributes)) {
await conversationJobQueue.add(
{
type: conversationQueueJobEnum.enum.Story,
conversationId: conversation.id,
messageIds: [message.id],
// using the group timestamp, which will differ from the 1:1 timestamp
timestamp: message.attributes.timestamp,
},
async jobToInsert => {
await DataWriter.saveMessage(message.attributes, {
jobToInsert,
ourAci: window.textsecure.storage.user.getCheckedAci(),
postSaveUpdates,
});
}
);
} else {
await conversationJobQueue.add(
{
type: conversationQueueJobEnum.enum.NormalMessage,
conversationId: conversation.id,
messageId: message.id,
revision: conversation.get('revision'),
},
async jobToInsert => {
await DataWriter.saveMessage(message.attributes, {
jobToInsert,
ourAci: window.textsecure.storage.user.getCheckedAci(),
postSaveUpdates,
});
}
);
}
dispatch({
type: 'NOOP',
@@ -2435,15 +2521,12 @@ export function copyMessageText(
messageId: string
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
messageId,
'copyMessageText'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`copy: Message ${messageId} missing!`);
}
const body = message.getNotificationText();
const body = getNotificationTextForMessage(message.attributes);
clipboard.writeText(body);
dispatch({
@@ -2457,10 +2540,7 @@ export function retryDeleteForEveryone(
messageId: string
): ThunkAction<void, RootStateType, unknown, NoopActionType> {
return async dispatch => {
const message = await __DEPRECATED$getMessageById(
messageId,
'retryDeleteForEveryone'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`retryDeleteForEveryone: Message ${messageId} missing!`);
}
@@ -2472,7 +2552,9 @@ export function retryDeleteForEveryone(
}
try {
const conversation = message.getConversation();
const conversation = window.ConversationController.get(
message.get('conversationId')
);
if (!conversation) {
throw new Error(
`retryDeleteForEveryone: Conversation for ${messageId} missing!`
@@ -2489,7 +2571,7 @@ export function retryDeleteForEveryone(
};
log.info(
`retryDeleteForEveryone: Adding job for message ${message.idForLogging()}!`
`retryDeleteForEveryone: Adding job for message ${getMessageIdForLogging(message.attributes)}!`
);
await conversationJobQueue.add(jobData);
@@ -3247,12 +3329,7 @@ function pushPanelForConversation(
const message =
conversations.messagesLookup[messageId] ||
(
await __DEPRECATED$getMessageById(
messageId,
'pushPanelForConversation'
)
)?.attributes;
(await getMessageById(messageId))?.attributes;
if (!message) {
throw new Error(
'pushPanelForConversation: could not find message for MessageDetails'
@@ -3328,17 +3405,16 @@ function deleteMessagesForEveryone(
await Promise.all(
messageIds.map(async messageId => {
try {
const message = window.MessageCache.__DEPRECATED$getById(
messageId,
'deleteMessagesForEveryone'
);
const message = window.MessageCache.getById(messageId);
if (!message) {
throw new Error(
`deleteMessageForEveryone: Message ${messageId} missing!`
);
}
const conversation = message.getConversation();
const conversation = window.ConversationController.get(
message.get('conversationId')
);
if (!conversation) {
throw new Error('deleteMessageForEveryone: no conversation');
}
@@ -3834,11 +3910,7 @@ function loadRecentMediaItems(
// Cache these messages in memory to ensure Lightbox can find them
messages.forEach(message => {
window.MessageCache.__DEPRECATED$register(
message.id,
message,
'loadRecentMediaItems'
);
window.MessageCache.register(new MessageModel(message));
});
let index = 0;
@@ -4042,10 +4114,7 @@ export function saveAttachmentFromMessage(
providedAttachment?: AttachmentType
): ThunkAction<void, RootStateType, unknown, ShowToastActionType> {
return async (dispatch, getState) => {
const message = await __DEPRECATED$getMessageById(
messageId,
'saveAttachmentFromMessage'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(
`saveAttachmentFromMessage: Message ${messageId} missing!`
@@ -4138,10 +4207,7 @@ export function scrollToMessage(
throw new Error('scrollToMessage: No conversation found');
}
const message = await __DEPRECATED$getMessageById(
messageId,
'scrollToMessage'
);
const message = await getMessageById(messageId);
if (!message) {
throw new Error(`scrollToMessage: failed to load message ${messageId}`);
}
@@ -4155,12 +4221,7 @@ export function scrollToMessage(
let isInMemory = true;
if (
!window.MessageCache.__DEPRECATED$getById(
messageId,
'scrollToMessage/notInMemory'
)
) {
if (!window.MessageCache.getById(messageId)) {
isInMemory = false;
}
@@ -4591,10 +4652,7 @@ function onConversationOpened(
log.info(`${logId}: Updating newly opened conversation state`);
if (messageId) {
const message = await __DEPRECATED$getMessageById(
messageId,
'onConversationOpened'
);
const message = await getMessageById(messageId);
if (message) {
drop(conversation.loadAndScroll(messageId));
@@ -4733,12 +4791,9 @@ function showArchivedConversations(): ShowArchivedConversationsActionType {
}
function doubleCheckMissingQuoteReference(messageId: string): NoopActionType {
const message = window.MessageCache.__DEPRECATED$getById(
messageId,
'doubleCheckMissingQuoteReference'
);
const message = window.MessageCache.getById(messageId);
if (message) {
void message.doubleCheckMissingQuoteReference();
drop(doDoubleCheckMissingQuoteReference(message));
}
return {