diff --git a/keyserver/src/creators/message-creator.js b/keyserver/src/creators/message-creator.js --- a/keyserver/src/creators/message-creator.js +++ b/keyserver/src/creators/message-creator.js @@ -38,7 +38,7 @@ } from '../fetchers/message-fetchers.js'; import { fetchOtherSessionsForViewer } from '../fetchers/session-fetchers.js'; import { fetchServerThreadInfos } from '../fetchers/thread-fetchers.js'; -import { sendPushNotifs } from '../push/send.js'; +import { sendPushNotifs, sendRescindNotifs } from '../push/send.js'; import { handleAsyncPromise } from '../responders/handlers.js'; import type { Viewer } from '../session/viewer.js'; import { earliestFocusedTimeConsideredExpired } from '../shared/focused-times.js'; @@ -148,8 +148,9 @@ subthreadPermissionsToCheck.add(messageData.childThreadID); } - const content = - messageSpecs[messageData.type].messageContentForServerDB?.(messageData); + const content = messageSpecs[messageData.type].messageContentForServerDB?.( + messageData, + ); const creation = messageData.localID && viewer.hasSessionInfo @@ -393,6 +394,8 @@ const messageInfosPerUser = {}; const latestMessagesPerUser: LatestMessagesPerUser = new Map(); const userPushInfoPromises = {}; + const userRescindInfoPromises = {}; + for (const pair of perUserInfo) { const [userID, preUserPushInfo] = pair; @@ -475,20 +478,26 @@ }; const userPushInfoPromise = generateNotifUserInfoPromise(pushTypes.NOTIF); + const userRescindInfoPromise = generateNotifUserInfoPromise( + pushTypes.RESCIND, + ); userPushInfoPromises[userID] = userPushInfoPromise; + userRescindInfoPromises[userID] = userRescindInfoPromise; } const latestMessages = flattenLatestMessagesPerUser(latestMessagesPerUser); - const [pushInfo] = await Promise.all([ + const [pushInfo, rescindInfo] = await Promise.all([ promiseAll(userPushInfoPromises), + promiseAll(userRescindInfoPromises), createReadStatusUpdates(latestMessages), redisPublish(viewer, messageInfosPerUser, updatesForCurrentSession), updateLatestMessages(latestMessages), ]); await sendPushNotifs(_pickBy(Boolean)(pushInfo)); + await sendRescindNotifs(_pickBy(Boolean)(rescindInfo)); } async function redisPublish( @@ -533,8 +542,11 @@ threadsToMessageIndices: $ReadOnlyMap>, messageInfos: $ReadOnlyArray, ) { - const { threadIDs, notFocusedThreadIDs, subthreadsCanSetToUnread } = - preUserPushInfo; + const { + threadIDs, + notFocusedThreadIDs, + subthreadsCanSetToUnread, + } = preUserPushInfo; const latestMessagesPerThread = new Map(); for (const threadID of threadIDs) { const messageIndices = threadsToMessageIndices.get(threadID); diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js --- a/keyserver/src/push/send.js +++ b/keyserver/src/push/send.js @@ -33,6 +33,7 @@ import { promiseAll } from 'lib/utils/promises.js'; import { getAPNsNotificationTopic } from './providers.js'; +import { rescindPushNotifs } from './rescind.js'; import { apnPush, fcmPush, @@ -244,6 +245,41 @@ await saveNotifResults(deliveryResults, notifications, true); } +async function sendRescindNotifs(rescindInfo: PushInfo) { + if (Object.keys(rescindInfo).length === 0) { + return; + } + + const [{ usersToCollapsableNotifInfo }] = await Promise.all([ + fetchInfos(rescindInfo), + ]); + + const promises = []; + for (const userID in usersToCollapsableNotifInfo) { + for (const notifInfo of usersToCollapsableNotifInfo[userID]) { + if (notifInfo.existingMessageInfos.length === 0) { + continue; + } + + for (const existingMessageInfo of notifInfo.existingMessageInfos) { + const rescindCondition = SQL` + n.user = ${userID} AND + n.thread = ${existingMessageInfo.threadID} AND + n.message = ${existingMessageInfo.id} + `; + + const inputCountCondition = SQL` + IF(m.thread = ${existingMessageInfo.threadID}, NULL, m.thread) + `; + + promises.push(rescindPushNotifs(rescindCondition, inputCountCondition)); + } + } + } + + await Promise.all(promises); +} + // The results in deliveryResults will be combined with the rows // in rowsToSave and then written to the notifications table async function saveNotifResults( @@ -840,4 +876,4 @@ await saveNotifResults(deliveryResults, new Map(), false); } -export { sendPushNotifs, updateBadgeCount }; +export { sendPushNotifs, sendRescindNotifs, updateBadgeCount };