Page MenuHomePhabricator

D12477.id41948.diff
No OneTemporary

D12477.id41948.diff

diff --git a/lib/push/send-hooks.react.js b/lib/push/send-hooks.react.js
--- a/lib/push/send-hooks.react.js
+++ b/lib/push/send-hooks.react.js
@@ -4,16 +4,22 @@
import {
preparePushNotifs,
- type PerUserNotifBuildResult,
+ type PerUserTargetedNotifications,
} from './send-utils.js';
import { ENSCacheContext } from '../components/ens-cache-provider.react.js';
import { NeynarClientContext } from '../components/neynar-client-provider.react.js';
import type { MessageData } from '../types/message-types.js';
+import type {
+ EncryptedNotifUtilsAPI,
+ SenderDeviceDescriptor,
+} from '../types/notif-types.js';
import { useSelector } from '../utils/redux-utils.js';
function usePreparePushNotifs(): (
+ encryptedNotifsUtilsAPI: EncryptedNotifUtilsAPI,
+ senderDeviceDescriptor: SenderDeviceDescriptor,
messageDatas: $ReadOnlyArray<MessageData>,
-) => Promise<?PerUserNotifBuildResult> {
+) => Promise<?PerUserTargetedNotifications> {
const rawMessageInfos = useSelector(state => state.messageStore.messages);
const rawThreadInfos = useSelector(state => state.threadStore.threadInfos);
const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos);
@@ -23,8 +29,14 @@
const getFCNames = React.useContext(NeynarClientContext)?.getFCNames;
return React.useCallback(
- (messageDatas: $ReadOnlyArray<MessageData>) => {
+ (
+ encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
+ senderDeviceDescriptor: SenderDeviceDescriptor,
+ messageDatas: $ReadOnlyArray<MessageData>,
+ ) => {
return preparePushNotifs({
+ encryptedNotifUtilsAPI,
+ senderDeviceDescriptor,
messageInfos: rawMessageInfos,
rawThreadInfos,
auxUserInfos,
diff --git a/lib/push/send-utils.js b/lib/push/send-utils.js
--- a/lib/push/send-utils.js
+++ b/lib/push/send-utils.js
@@ -3,11 +3,20 @@
import _pickBy from 'lodash/fp/pickBy.js';
import uuidv4 from 'uuid/v4.js';
-import { generateNotifUserInfoPromise } from './utils.js';
+import { createAndroidVisualNotification } from './android-notif-creators.js';
+import { createAPNsVisualNotification } from './apns-notif-creators.js';
+import {
+ stringToVersionKey,
+ getDevicesByPlatform,
+ generateNotifUserInfoPromise,
+} from './utils.js';
+import { createWebNotification } from './web-notif-creators.js';
+import { createWNSNotification } from './wns-notif-creators.js';
import { hasPermission } from '../permissions/minimally-encoded-thread-permissions.js';
import {
rawMessageInfoFromMessageData,
createMessageInfo,
+ shimUnsupportedRawMessageInfos,
} from '../shared/message-utils.js';
import { pushTypes } from '../shared/messages/message-spec.js';
import { messageSpecs } from '../shared/messages/message-specs.js';
@@ -17,7 +26,7 @@
threadInfoFromRawThreadInfo,
} from '../shared/thread-utils.js';
import type { AuxUserInfos } from '../types/aux-user-types.js';
-import type { PlatformDetails } from '../types/device-types.js';
+import type { PlatformDetails, Platform } from '../types/device-types.js';
import {
identityDeviceTypeToPlatform,
type IdentityPlatformDetails,
@@ -28,7 +37,13 @@
messageDataLocalID,
} from '../types/message-types.js';
import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
-import type { ResolvedNotifTexts } from '../types/notif-types.js';
+import type {
+ ResolvedNotifTexts,
+ NotificationTargetDevice,
+ TargetedNotificationWithPlatform,
+ SenderDeviceDescriptor,
+ EncryptedNotifUtilsAPI,
+} from '../types/notif-types.js';
import type { RawThreadInfos } from '../types/thread-types.js';
import type { UserInfos } from '../types/user-types.js';
import { type GetENSNames } from '../utils/ens-helpers.js';
@@ -187,19 +202,16 @@
}
async function buildNotifText(
- inputData: {
- +rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
- +userID: string,
- +threadInfos: { +[id: string]: ThreadInfo },
- +userInfos: UserInfos,
- },
+ rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
+ userID: string,
+ threadInfos: { +[id: string]: ThreadInfo },
+ userInfos: UserInfos,
getENSNames: ?GetENSNames,
getFCNames: ?GetFCNames,
): Promise<?{
+notifTexts: ResolvedNotifTexts,
+newRawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
}> {
- const { rawMessageInfos, userID, threadInfos, userInfos } = inputData;
const hydrateMessageInfo = (rawMessageInfo: RawMessageInfo) =>
createMessageInfo(rawMessageInfo, userID, userInfos, threadInfos);
@@ -243,20 +255,277 @@
return { notifTexts, newRawMessageInfos };
}
-export type PerUserNotifBuildResult = {
- +[userID: string]: $ReadOnlyArray<{
- +notifTexts: ResolvedNotifTexts,
- +newRawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
- }>,
+type BuildNotifsForUserDevicesInputData = {
+ +encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
+ +senderDeviceDescriptor: SenderDeviceDescriptor,
+ +rawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
+ +userID: string,
+ +threadInfos: { +[id: string]: ThreadInfo },
+ +userInfos: UserInfos,
+ +getENSNames: ?GetENSNames,
+ +getFCNames: ?GetFCNames,
+ +devicesByPlatform: $ReadOnlyMap<
+ Platform,
+ $ReadOnlyMap<string, $ReadOnlyArray<NotificationTargetDevice>>,
+ >,
};
-async function buildNotifsTexts(
- pushInfo: PushInfo,
- rawThreadInfos: RawThreadInfos,
- userInfos: UserInfos,
- getENSNames: ?GetENSNames,
- getFCNames: ?GetFCNames,
-): Promise<PerUserNotifBuildResult> {
+async function buildNotifsForUserDevices(
+ inputData: BuildNotifsForUserDevicesInputData,
+): Promise<?$ReadOnlyArray<TargetedNotificationWithPlatform>> {
+ const {
+ encryptedNotifUtilsAPI,
+ senderDeviceDescriptor,
+ rawMessageInfos,
+ userID,
+ threadInfos,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ devicesByPlatform,
+ } = inputData;
+
+ const notifTextWithNewRawMessageInfos = await buildNotifText(
+ rawMessageInfos,
+ userID,
+ threadInfos,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ );
+
+ if (!notifTextWithNewRawMessageInfos) {
+ return null;
+ }
+
+ const { notifTexts, newRawMessageInfos } = notifTextWithNewRawMessageInfos;
+ const [{ threadID }] = newRawMessageInfos;
+
+ const promises: Array<
+ Promise<$ReadOnlyArray<TargetedNotificationWithPlatform>>,
+ > = [];
+
+ const iosVersionToDevices = devicesByPlatform.get('ios');
+ if (iosVersionToDevices) {
+ for (const [versionKey, devices] of iosVersionToDevices) {
+ const { codeVersion, stateVersion } = stringToVersionKey(versionKey);
+ const platformDetails = {
+ platform: 'ios',
+ codeVersion,
+ stateVersion,
+ };
+ const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos(
+ newRawMessageInfos,
+ platformDetails,
+ );
+
+ promises.push(
+ (async () => {
+ return (
+ await createAPNsVisualNotification(
+ encryptedNotifUtilsAPI,
+ {
+ senderDeviceDescriptor,
+ notifTexts,
+ newRawMessageInfos: shimmedNewRawMessageInfos,
+ threadID,
+ collapseKey: undefined,
+ badgeOnly: false,
+ unreadCount: undefined,
+ platformDetails,
+ uniqueID: uuidv4(),
+ },
+ devices,
+ )
+ ).map(targetedNotification => ({
+ platform: 'ios',
+ targetedNotification,
+ }));
+ })(),
+ );
+ }
+ }
+
+ const androidVersionToDevices = devicesByPlatform.get('android');
+ if (androidVersionToDevices) {
+ for (const [versionKey, devices] of androidVersionToDevices) {
+ const { codeVersion, stateVersion } = stringToVersionKey(versionKey);
+ const platformDetails = {
+ platform: 'android',
+ codeVersion,
+ stateVersion,
+ };
+ const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos(
+ newRawMessageInfos,
+ platformDetails,
+ );
+
+ promises.push(
+ (async () => {
+ return (
+ await createAndroidVisualNotification(
+ encryptedNotifUtilsAPI,
+ {
+ senderDeviceDescriptor,
+ notifTexts,
+ newRawMessageInfos: shimmedNewRawMessageInfos,
+ threadID,
+ collapseKey: undefined,
+ badgeOnly: false,
+ unreadCount: undefined,
+ platformDetails,
+ notifID: uuidv4(),
+ },
+ devices,
+ )
+ ).map(targetedNotification => ({
+ platform: 'android',
+ targetedNotification,
+ }));
+ })(),
+ );
+ }
+ }
+
+ const macosVersionToDevices = devicesByPlatform.get('macos');
+ if (macosVersionToDevices) {
+ for (const [versionKey, devices] of macosVersionToDevices) {
+ const { codeVersion, stateVersion, majorDesktopVersion } =
+ stringToVersionKey(versionKey);
+ const platformDetails = {
+ platform: 'macos',
+ codeVersion,
+ stateVersion,
+ majorDesktopVersion,
+ };
+ const shimmedNewRawMessageInfos = shimUnsupportedRawMessageInfos(
+ newRawMessageInfos,
+ platformDetails,
+ );
+
+ promises.push(
+ (async () => {
+ return (
+ await createAPNsVisualNotification(
+ encryptedNotifUtilsAPI,
+ {
+ senderDeviceDescriptor,
+ notifTexts,
+ newRawMessageInfos: shimmedNewRawMessageInfos,
+ threadID,
+ collapseKey: undefined,
+ badgeOnly: false,
+ unreadCount: undefined,
+ platformDetails,
+ uniqueID: uuidv4(),
+ },
+ devices,
+ )
+ ).map(targetedNotification => ({
+ platform: 'macos',
+ targetedNotification,
+ }));
+ })(),
+ );
+ }
+ }
+
+ const windowsVersionToDevices = devicesByPlatform.get('windows');
+ if (windowsVersionToDevices) {
+ for (const [versionKey, devices] of windowsVersionToDevices) {
+ const { codeVersion, stateVersion, majorDesktopVersion } =
+ stringToVersionKey(versionKey);
+ const platformDetails = {
+ platform: 'windows',
+ codeVersion,
+ stateVersion,
+ majorDesktopVersion,
+ };
+
+ promises.push(
+ (async () => {
+ return (
+ await createWNSNotification(
+ encryptedNotifUtilsAPI,
+ {
+ notifTexts,
+ threadID,
+ senderDeviceDescriptor,
+ platformDetails,
+ },
+ devices,
+ )
+ ).map(targetedNotification => ({
+ platform: 'windows',
+ targetedNotification,
+ }));
+ })(),
+ );
+ }
+ }
+
+ const webVersionToDevices = devicesByPlatform.get('web');
+ if (webVersionToDevices) {
+ for (const [versionKey, devices] of webVersionToDevices) {
+ const { codeVersion, stateVersion } = stringToVersionKey(versionKey);
+ const platformDetails = {
+ platform: 'web',
+ codeVersion,
+ stateVersion,
+ };
+
+ promises.push(
+ (async () => {
+ return (
+ await createWebNotification(
+ encryptedNotifUtilsAPI,
+ {
+ notifTexts,
+ threadID,
+ senderDeviceDescriptor,
+ platformDetails,
+ id: uuidv4(),
+ },
+ devices,
+ )
+ ).map(targetedNotification => ({
+ platform: 'web',
+ targetedNotification,
+ }));
+ })(),
+ );
+ }
+ }
+
+ return (await Promise.all(promises)).flat();
+}
+
+export type PerUserTargetedNotifications = {
+ +[userID: string]: $ReadOnlyArray<TargetedNotificationWithPlatform>,
+};
+
+type BuildNotifsFromPushInfoInputData = {
+ +encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
+ +senderDeviceDescriptor: SenderDeviceDescriptor,
+ +pushInfo: PushInfo,
+ +rawThreadInfos: RawThreadInfos,
+ +userInfos: UserInfos,
+ +getENSNames: ?GetENSNames,
+ +getFCNames: ?GetFCNames,
+};
+
+async function buildNotifsFromPushInfo(
+ inputData: BuildNotifsFromPushInfoInputData,
+): Promise<PerUserTargetedNotifications> {
+ const {
+ encryptedNotifUtilsAPI,
+ senderDeviceDescriptor,
+ pushInfo,
+ rawThreadInfos,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ } = inputData;
const threadIDs = new Set<string>();
for (const userID in pushInfo) {
@@ -273,13 +542,8 @@
}
}
- const perUserNotifTextsPromises: {
- [userID: string]: Promise<
- Array<?{
- +notifTexts: ResolvedNotifTexts,
- +newRawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
- }>,
- >,
+ const perUserBuildNotifsResultPromises: {
+ [userID: string]: Promise<$ReadOnlyArray<TargetedNotificationWithPlatform>>,
} = {};
for (const userID in pushInfo) {
@@ -293,41 +557,42 @@
),
]),
);
-
- const userNotifTextsPromises = [];
+ const devicesByPlatform = getDevicesByPlatform(pushInfo[userID].devices);
+ const singleNotificationPromises = [];
for (const rawMessageInfos of pushInfo[userID].messageInfos) {
- userNotifTextsPromises.push(
- buildNotifText(
- {
- // We always pass one element array here
- // because coalescing is not supported for
- // notifications generated on the client
- rawMessageInfos: [rawMessageInfos],
- threadInfos,
- userID,
- userInfos,
- },
+ singleNotificationPromises.push(
+ // We always pass one element array here
+ // because coalescing is not supported for
+ // notifications generated on the client
+ buildNotifsForUserDevices({
+ encryptedNotifUtilsAPI,
+ senderDeviceDescriptor,
+ rawMessageInfos: [rawMessageInfos],
+ userID,
+ threadInfos,
+ userInfos,
getENSNames,
getFCNames,
- ),
+ devicesByPlatform,
+ }),
);
}
- perUserNotifTextsPromises[userID] = Promise.all(userNotifTextsPromises);
+ perUserBuildNotifsResultPromises[userID] = (async () => {
+ const singleNotificationResults = await Promise.all(
+ singleNotificationPromises,
+ );
+ return singleNotificationResults.filter(Boolean).flat();
+ })();
}
- const perUserNotifTexts = await promiseAll(perUserNotifTextsPromises);
- const filteredPerUserNotifTexts: { ...PerUserNotifBuildResult } = {};
-
- for (const userID in perUserNotifTexts) {
- filteredPerUserNotifTexts[userID] =
- perUserNotifTexts[userID].filter(Boolean);
- }
- return filteredPerUserNotifTexts;
+ return promiseAll(perUserBuildNotifsResultPromises);
}
type PreparePushNotifsInputData = {
+ +encryptedNotifUtilsAPI: EncryptedNotifUtilsAPI,
+ +senderDeviceDescriptor: SenderDeviceDescriptor,
+messageInfos: { +[id: string]: RawMessageInfo },
+rawThreadInfos: RawThreadInfos,
+auxUserInfos: AuxUserInfos,
@@ -339,8 +604,10 @@
async function preparePushNotifs(
inputData: PreparePushNotifsInputData,
-): Promise<?PerUserNotifBuildResult> {
+): Promise<?PerUserTargetedNotifications> {
const {
+ encryptedNotifUtilsAPI,
+ senderDeviceDescriptor,
messageDatas,
messageInfos,
auxUserInfos,
@@ -361,13 +628,15 @@
return null;
}
- return await buildNotifsTexts(
- pushInfos,
+ return await buildNotifsFromPushInfo({
+ encryptedNotifUtilsAPI,
+ senderDeviceDescriptor,
+ pushInfo: pushInfos,
rawThreadInfos,
userInfos,
getENSNames,
getFCNames,
- );
+ });
}
export { preparePushNotifs, generateNotifUserInfoPromise };
diff --git a/lib/push/web-notif-creators.js b/lib/push/web-notif-creators.js
--- a/lib/push/web-notif-creators.js
+++ b/lib/push/web-notif-creators.js
@@ -21,7 +21,7 @@
+notifTexts: ResolvedNotifTexts,
+threadID: string,
+senderDeviceDescriptor: SenderDeviceDescriptor,
- +unreadCount: number,
+ +unreadCount?: number,
+platformDetails: PlatformDetails,
};
@@ -31,7 +31,7 @@
notifTexts: resolvedNotifTextsValidator,
threadID: tID,
senderDeviceDescriptor: senderDeviceDescriptorValidator,
- unreadCount: t.Number,
+ unreadCount: t.maybe(t.Number),
platformDetails: tPlatformDetails,
});
diff --git a/lib/push/wns-notif-creators.js b/lib/push/wns-notif-creators.js
--- a/lib/push/wns-notif-creators.js
+++ b/lib/push/wns-notif-creators.js
@@ -22,7 +22,7 @@
+notifTexts: ResolvedNotifTexts,
+threadID: string,
+senderDeviceDescriptor: SenderDeviceDescriptor,
- +unreadCount: number,
+ +unreadCount?: number,
+platformDetails: PlatformDetails,
};
@@ -31,7 +31,7 @@
notifTexts: resolvedNotifTextsValidator,
threadID: tID,
senderDeviceDescriptor: senderDeviceDescriptorValidator,
- unreadCount: t.Number,
+ unreadCount: t.maybe(t.Number),
platformDetails: tPlatformDetails,
});
diff --git a/lib/types/notif-types.js b/lib/types/notif-types.js
--- a/lib/types/notif-types.js
+++ b/lib/types/notif-types.js
@@ -3,6 +3,7 @@
import type { EncryptResult } from '@commapp/olm';
import t, { type TInterface, type TUnion } from 'tcomb';
+import type { Platform } from './device-types.js';
import type { EntityText, ThreadEntity } from '../utils/entity-text.js';
import { tShape } from '../utils/validation-utils.js';
@@ -42,7 +43,7 @@
+body: string,
+prefix?: string,
+title: string,
- +unreadCount: number,
+ +unreadCount?: number,
+threadID: string,
+encryptionFailed?: '1',
};
@@ -68,7 +69,7 @@
+body: string,
+prefix?: string,
+title: string,
- +unreadCount: number,
+ +unreadCount?: number,
+threadID: string,
+encryptionFailed?: '1',
};
@@ -361,6 +362,15 @@
+blobHolder?: string,
};
+export type TargetedNotificationWithPlatform = {
+ +platform: Platform,
+ +targetedNotification:
+ | TargetedAPNsNotification
+ | TargetedWNSNotification
+ | TargetedWebNotification
+ | TargetedAndroidNotification,
+};
+
export type EncryptedNotifUtilsAPI = {
+encryptSerializedNotifPayload: (
cryptoID: string,

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 17, 4:37 AM (18 h, 37 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2495761
Default Alt Text
D12477.id41948.diff (18 KB)

Event Timeline