Page MenuHomePhabricator

D12464.id41946.diff
No OneTemporary

D12464.id41946.diff

diff --git a/lib/push/send-hooks.react.js b/lib/push/send-hooks.react.js
new file mode 100644
--- /dev/null
+++ b/lib/push/send-hooks.react.js
@@ -0,0 +1,48 @@
+// @flow
+
+import * as React from 'react';
+
+import {
+ preparePushNotifs,
+ type PerUserNotifBuildResult,
+} 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 { useSelector } from '../utils/redux-utils.js';
+
+function usePreparePushNotifs(): (
+ messageDatas: $ReadOnlyArray<MessageData>,
+) => Promise<?PerUserNotifBuildResult> {
+ const rawMessageInfos = useSelector(state => state.messageStore.messages);
+ const rawThreadInfos = useSelector(state => state.threadStore.threadInfos);
+ const auxUserInfos = useSelector(state => state.auxUserStore.auxUserInfos);
+ const userInfos = useSelector(state => state.userStore.userInfos);
+
+ const { getENSNames } = React.useContext(ENSCacheContext);
+ const getFCNames = React.useContext(NeynarClientContext)?.getFCNames;
+
+ return React.useCallback(
+ (messageDatas: $ReadOnlyArray<MessageData>) => {
+ return preparePushNotifs({
+ messageInfos: rawMessageInfos,
+ rawThreadInfos,
+ auxUserInfos,
+ messageDatas,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ });
+ },
+ [
+ rawMessageInfos,
+ rawThreadInfos,
+ auxUserInfos,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ ],
+ );
+}
+
+export { usePreparePushNotifs };
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
@@ -5,10 +5,17 @@
import uuidv4 from 'uuid/v4.js';
import { hasPermission } from '../permissions/minimally-encoded-thread-permissions.js';
-import { rawMessageInfoFromMessageData } from '../shared/message-utils.js';
+import {
+ rawMessageInfoFromMessageData,
+ createMessageInfo,
+} from '../shared/message-utils.js';
import { type PushType, pushTypes } from '../shared/messages/message-spec.js';
import { messageSpecs } from '../shared/messages/message-specs.js';
-import { isMemberActive } from '../shared/thread-utils.js';
+import { notifTextsForMessageInfo } from '../shared/notif-utils.js';
+import {
+ isMemberActive,
+ threadInfoFromRawThreadInfo,
+} from '../shared/thread-utils.js';
import type { AuxUserInfos } from '../types/aux-user-types.js';
import type { PlatformDetails } from '../types/device-types.js';
import {
@@ -20,7 +27,12 @@
type RawMessageInfo,
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 { RawThreadInfos } from '../types/thread-types.js';
+import type { UserInfos } from '../types/user-types.js';
+import { type GetENSNames } from '../utils/ens-helpers.js';
+import { type GetFCNames } from '../utils/farcaster-helpers.js';
import { promiseAll } from '../utils/promises.js';
export type Device = {
@@ -266,4 +278,188 @@
};
}
-export { getPushUserInfo, generateNotifUserInfoPromise };
+async function buildNotifText(
+ inputData: {
+ +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);
+
+ const newMessageInfos = [];
+ const newRawMessageInfos = [];
+
+ for (const rawMessageInfo of rawMessageInfos) {
+ const newMessageInfo = hydrateMessageInfo(rawMessageInfo);
+ if (newMessageInfo) {
+ newMessageInfos.push(newMessageInfo);
+ newRawMessageInfos.push(rawMessageInfo);
+ }
+ }
+
+ if (newMessageInfos.length === 0) {
+ return null;
+ }
+
+ const [{ threadID }] = newMessageInfos;
+ const threadInfo = threadInfos[threadID];
+ const parentThreadInfo = threadInfo.parentThreadID
+ ? threadInfos[threadInfo.parentThreadID]
+ : null;
+
+ // TODO: Using types from @Ashoat check ThreadSubscription and mentioning
+
+ const username = userInfos[userID] && userInfos[userID].username;
+ const notifTargetUserInfo = { id: userID, username };
+ const notifTexts = await notifTextsForMessageInfo(
+ newMessageInfos,
+ threadInfo,
+ parentThreadInfo,
+ notifTargetUserInfo,
+ getENSNames,
+ getFCNames,
+ );
+ if (!notifTexts) {
+ return null;
+ }
+
+ return { notifTexts, newRawMessageInfos };
+}
+
+export type PerUserNotifBuildResult = {
+ +[userID: string]: $ReadOnlyArray<{
+ +notifTexts: ResolvedNotifTexts,
+ +newRawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
+ }>,
+};
+
+async function buildNotifsTexts(
+ pushInfo: PushInfo,
+ rawThreadInfos: RawThreadInfos,
+ userInfos: UserInfos,
+ getENSNames: ?GetENSNames,
+ getFCNames: ?GetFCNames,
+): Promise<PerUserNotifBuildResult> {
+ const threadIDs = new Set<string>();
+
+ for (const userID in pushInfo) {
+ for (const rawMessageInfo of pushInfo[userID].messageInfos) {
+ const threadID = rawMessageInfo.threadID;
+ threadIDs.add(threadID);
+
+ const messageSpec = messageSpecs[rawMessageInfo.type];
+ if (messageSpec.threadIDs) {
+ for (const id of messageSpec.threadIDs(rawMessageInfo)) {
+ threadIDs.add(id);
+ }
+ }
+ }
+ }
+
+ const perUserNotifTextsPromises: {
+ [userID: string]: Promise<
+ Array<?{
+ +notifTexts: ResolvedNotifTexts,
+ +newRawMessageInfos: $ReadOnlyArray<RawMessageInfo>,
+ }>,
+ >,
+ } = {};
+
+ for (const userID in pushInfo) {
+ const threadInfos = Object.fromEntries(
+ [...threadIDs].map(threadID => [
+ threadID,
+ threadInfoFromRawThreadInfo(
+ rawThreadInfos[threadID],
+ userID,
+ userInfos,
+ ),
+ ]),
+ );
+
+ const userNotifTextsPromises = [];
+
+ 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,
+ },
+ getENSNames,
+ getFCNames,
+ ),
+ );
+ }
+
+ perUserNotifTextsPromises[userID] = Promise.all(userNotifTextsPromises);
+ }
+
+ const perUserNotifTexts = await promiseAll(perUserNotifTextsPromises);
+ const filteredPerUserNotifTexts: { ...PerUserNotifBuildResult } = {};
+
+ for (const userID in perUserNotifTexts) {
+ filteredPerUserNotifTexts[userID] =
+ perUserNotifTexts[userID].filter(Boolean);
+ }
+ return filteredPerUserNotifTexts;
+}
+
+type PreparePushNotifsInputData = {
+ +messageInfos: { +[id: string]: RawMessageInfo },
+ +rawThreadInfos: RawThreadInfos,
+ +auxUserInfos: AuxUserInfos,
+ +messageDatas: $ReadOnlyArray<MessageData>,
+ +userInfos: UserInfos,
+ +getENSNames: ?GetENSNames,
+ +getFCNames: ?GetFCNames,
+};
+
+async function preparePushNotifs(
+ inputData: PreparePushNotifsInputData,
+): Promise<?PerUserNotifBuildResult> {
+ const {
+ messageDatas,
+ messageInfos,
+ auxUserInfos,
+ rawThreadInfos,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ } = inputData;
+
+ const { pushInfos } = await getPushUserInfo(
+ messageInfos,
+ rawThreadInfos,
+ auxUserInfos,
+ messageDatas,
+ );
+
+ if (!pushInfos) {
+ return null;
+ }
+
+ return await buildNotifsTexts(
+ pushInfos,
+ rawThreadInfos,
+ userInfos,
+ getENSNames,
+ getFCNames,
+ );
+}
+
+export { preparePushNotifs, generateNotifUserInfoPromise };

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 16, 7:12 PM (20 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2501139
Default Alt Text
D12464.id41946.diff (8 KB)

Event Timeline