Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F32098266
D15498.1765011396.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
D15498.1765011396.diff
View Options
diff --git a/lib/selectors/chat-selectors.js b/lib/selectors/chat-selectors.js
--- a/lib/selectors/chat-selectors.js
+++ b/lib/selectors/chat-selectors.js
@@ -29,7 +29,10 @@
type SidebarItem,
} from '../shared/sidebar-item-utils.js';
import { threadInChatList, threadIsPending } from '../shared/thread-utils.js';
-import { threadTypeIsSidebar } from '../shared/threads/thread-specs.js';
+import {
+ threadSpecs,
+ threadTypeIsSidebar,
+} from '../shared/threads/thread-specs.js';
import { messageTypes } from '../types/message-types-enum.js';
import {
type ComposableMessageInfo,
@@ -450,22 +453,29 @@
targetMessageEditMap.set(messageInfo.targetMessageID, messageInfo.text);
}
+ const threadInfo = threadInfos[threadID];
const targetMessagePinStatusMap = new Map<string, boolean>();
- // Once again, we iterate backwards to put the order of messages in
- // chronological order (i.e. oldest to newest) to handle pinned messages.
- // This is important because we want to make sure that the most recent pin
- // action is the one that is used to determine whether a message
- // is pinned or not.
- for (let i = messages.length - 1; i >= 0; i--) {
- const messageInfo = messages[i];
- if (messageInfo.type !== messageTypes.TOGGLE_PIN) {
- continue;
- }
+ if (threadSpecs[threadInfo.type].protocol().pinsStoredOnServer) {
+ // Once again, we iterate backwards to put the order of messages in
+ // chronological order (i.e. oldest to newest) to handle pinned messages.
+ // This is important because we want to make sure that the most recent pin
+ // action is the one that is used to determine whether a message
+ // is pinned or not.
+ for (let i = messages.length - 1; i >= 0; i--) {
+ const messageInfo = messages[i];
+ if (messageInfo.type !== messageTypes.TOGGLE_PIN) {
+ continue;
+ }
- targetMessagePinStatusMap.set(
- messageInfo.targetMessageID,
- messageInfo.action === 'pin',
- );
+ targetMessagePinStatusMap.set(
+ messageInfo.targetMessageID,
+ messageInfo.action === 'pin',
+ );
+ }
+ } else {
+ for (const messageID of threadInfo.pinnedMessageIDs ?? []) {
+ targetMessagePinStatusMap.set(messageID, true);
+ }
}
const targetMessageDeleteStatusMap = new Map<string, boolean>();
@@ -602,7 +612,6 @@
return result;
})();
- const threadInfo = threadInfos[threadID];
const parentThreadInfo = threadInfo?.parentThreadID
? threadInfos[threadInfo.parentThreadID]
: null;
diff --git a/lib/shared/farcaster/farcaster-api.js b/lib/shared/farcaster/farcaster-api.js
--- a/lib/shared/farcaster/farcaster-api.js
+++ b/lib/shared/farcaster/farcaster-api.js
@@ -925,6 +925,40 @@
);
}
+export type PinMessageInput = {
+ +conversationId: string,
+ +messageId: string,
+};
+
+function usePinMessage(): (input: PinMessageInput) => Promise<void> {
+ const { sendFarcasterRequest } = useTunnelbroker();
+ const { addLog } = useDebugLogs();
+ return React.useCallback(
+ async (input: PinMessageInput) => {
+ try {
+ await sendFarcasterRequest({
+ apiVersion: 'v2',
+ endpoint: 'direct-cast-pin-message',
+ method: { type: 'POST' },
+ payload: JSON.stringify(input),
+ });
+ } catch (error) {
+ addLog(
+ 'Farcaster API: Failed to pin a message',
+ JSON.stringify({
+ conversationId: input.conversationId,
+ messageId: input.messageId,
+ error: getMessageForException(error),
+ }),
+ new Set([logTypes.FARCASTER, logTypes.ERROR]),
+ );
+ throw error;
+ }
+ },
+ [addLog, sendFarcasterRequest],
+ );
+}
+
export {
useSendFarcasterTextMessage,
useFetchFarcasterMessages,
@@ -942,4 +976,5 @@
useAcceptInvite,
useFetchFarcasterConversationInvites,
useAcceptOneOnOneInvite,
+ usePinMessage,
};
diff --git a/lib/shared/farcaster/farcaster-hooks.js b/lib/shared/farcaster/farcaster-hooks.js
--- a/lib/shared/farcaster/farcaster-hooks.js
+++ b/lib/shared/farcaster/farcaster-hooks.js
@@ -429,6 +429,8 @@
+farcasterConversation: FarcasterConversation,
+thread: FarcasterRawThreadInfo,
+threadMembers: Array<MemberInfoSansPermissions>,
+ +pinnedMessages: Array<RawMessageInfo>,
+ +userIDs: Array<string>,
};
async function fetchAndProcessConversation(
conversationID: string,
@@ -553,10 +555,23 @@
members: threadMembers,
};
+ const userFIDs = farcasterConversation.pinnedMessages.flatMap(message =>
+ extractFarcasterIDsFromPayload(farcasterMessageValidator, message),
+ );
+ const fetchedUserInfos = await fetchUsersByFIDs(userFIDs);
+ const pinnedMessages = farcasterConversation.pinnedMessages.flatMap(message =>
+ convertFarcasterMessageToCommMessages(message, fetchedUserInfos, addLog),
+ );
+ const userIDs = Array.from(fetchedUserInfos.entries()).map(
+ ([fid, user]) => user?.userID ?? userIDFromFID(fid),
+ );
+
return {
farcasterConversation,
thread,
threadMembers,
+ pinnedMessages,
+ userIDs,
};
}
@@ -615,6 +630,8 @@
threadMembers.forEach(member => batchedUpdates.addUserID(member.id));
}
batchedUpdates.addUpdateInfo(update);
+ batchedUpdates.addAdditionalMessageInfos(result.pinnedMessages);
+ batchedUpdates.addUserIDs(result.userIDs);
return farcasterConversation;
} catch (e) {
@@ -735,6 +752,8 @@
rawEntryInfos: [],
};
batchedUpdates.addUpdateInfo(update);
+ batchedUpdates.addAdditionalMessageInfos(result.pinnedMessages);
+ batchedUpdates.addUserIDs(result.userIDs);
return farcasterConversation;
} catch (e) {
diff --git a/lib/shared/thread-utils.js b/lib/shared/thread-utils.js
--- a/lib/shared/thread-utils.js
+++ b/lib/shared/thread-utils.js
@@ -952,6 +952,14 @@
if (pinnedCount) {
threadInfo = { ...threadInfo, pinnedCount };
}
+
+ if (rawThreadInfo.pinnedMessageIDs) {
+ threadInfo = {
+ ...threadInfo,
+ pinnedMessageIDs: rawThreadInfo.pinnedMessageIDs,
+ };
+ }
+
return threadInfo;
}
diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js
--- a/lib/shared/threads/protocols/dm-thread-protocol.js
+++ b/lib/shared/threads/protocols/dm-thread-protocol.js
@@ -954,6 +954,7 @@
supportsThreadRefreshing: false,
supportsMessageEdit: true,
supportsRelationships: true,
+ pinsStoredOnServer: false,
});
function pendingThreadType(numberOfOtherMembers: number) {
diff --git a/lib/shared/threads/protocols/farcaster-thread-protocol.js b/lib/shared/threads/protocols/farcaster-thread-protocol.js
--- a/lib/shared/threads/protocols/farcaster-thread-protocol.js
+++ b/lib/shared/threads/protocols/farcaster-thread-protocol.js
@@ -726,6 +726,13 @@
};
}
+ if (clientDBThreadInfo.pinnedMessageIDs) {
+ rawThreadInfo = {
+ ...rawThreadInfo,
+ pinnedMessageIDs: JSON.parse(clientDBThreadInfo.pinnedMessageIDs),
+ };
+ }
+
return rawThreadInfo;
},
@@ -1032,10 +1039,11 @@
supportsThreadRefreshing: true,
temporarilyDisabledFeatures: {
changingThreadAvatar: true,
- pinningMessages: true,
+ pinningMessages: false,
},
supportsMessageEdit: false,
supportsRelationships: false,
+ pinsStoredOnServer: false,
};
function pendingThreadType(numberOfOtherMembers: number) {
diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js
--- a/lib/shared/threads/protocols/keyserver-thread-protocol.js
+++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js
@@ -757,6 +757,7 @@
supportsThreadRefreshing: false,
supportsMessageEdit: true,
supportsRelationships: true,
+ pinsStoredOnServer: true,
});
function pendingThreadType(numberOfOtherMembers: number) {
diff --git a/lib/shared/threads/thread-spec.js b/lib/shared/threads/thread-spec.js
--- a/lib/shared/threads/thread-spec.js
+++ b/lib/shared/threads/thread-spec.js
@@ -559,6 +559,7 @@
},
+supportsMessageEdit: boolean,
+supportsRelationships: boolean,
+ +pinsStoredOnServer: boolean,
};
export type ThreadSpec<
diff --git a/lib/types/minimally-encoded-thread-permissions-types.js b/lib/types/minimally-encoded-thread-permissions-types.js
--- a/lib/types/minimally-encoded-thread-permissions-types.js
+++ b/lib/types/minimally-encoded-thread-permissions-types.js
@@ -279,6 +279,7 @@
+sourceMessageID?: string,
+repliesCount: number,
+pinnedCount?: number,
+ +pinnedMessageIDs?: $ReadOnlyArray<string>,
}>;
export type ResolvedThreadInfo = $ReadOnly<{
diff --git a/lib/types/thread-types.js b/lib/types/thread-types.js
--- a/lib/types/thread-types.js
+++ b/lib/types/thread-types.js
@@ -193,6 +193,7 @@
+currentUser: LegacyThreadCurrentUserInfo,
+repliesCount: number,
+pinnedCount?: number,
+ +pinnedMessageIDs?: $ReadOnlyArray<string>,
};
export type LegacyRawThreadInfo =
@@ -271,6 +272,7 @@
currentUser: legacyThreadCurrentUserInfoValidator,
repliesCount: t.Number,
pinnedCount: t.maybe(t.Number),
+ pinnedMessageIDs: t.maybe(t.list(tID)),
});
export const legacyThreadInfoValidator: TUnion<
@@ -347,6 +349,7 @@
+repliesCount: number,
+pinnedCount?: number,
+timestamps?: ?string,
+ +pinnedMessageIDs?: ?string,
};
export type ThreadDeletionRequest = {
diff --git a/lib/utils/convert-farcaster-message-to-comm-messages.js b/lib/utils/convert-farcaster-message-to-comm-messages.js
--- a/lib/utils/convert-farcaster-message-to-comm-messages.js
+++ b/lib/utils/convert-farcaster-message-to-comm-messages.js
@@ -23,7 +23,7 @@
function convertFarcasterMessageToCommMessages(
farcasterMessage: FarcasterMessage,
fcUserInfos: FCUserInfos,
- addLog: AddLogCallback,
+ addLog: ?AddLogCallback,
): $ReadOnlyArray<RawMessageInfo> {
const senderFid = farcasterMessage.senderFid.toString();
const creatorID =
@@ -194,8 +194,19 @@
time: parseInt(farcasterMessage.serverTimestamp, 10),
removedUserIDs: [removedUserID],
});
+ } else if (farcasterMessage.type === 'pin_message') {
+ result.push({
+ type: messageTypes.TOGGLE_PIN,
+ id: farcasterMessage.messageId,
+ threadID,
+ targetMessageID: farcasterMessage.message,
+ action: 'pin',
+ pinnedContent: 'a message',
+ creatorID,
+ time: parseInt(farcasterMessage.serverTimestamp, 10),
+ });
} else {
- addLog(
+ addLog?.(
'Unsupported Farcaster message',
`Unsupported message type: ${farcasterMessage.type}`,
new Set([logTypes.FARCASTER]),
diff --git a/lib/utils/create-farcaster-raw-thread-info.js b/lib/utils/create-farcaster-raw-thread-info.js
--- a/lib/utils/create-farcaster-raw-thread-info.js
+++ b/lib/utils/create-farcaster-raw-thread-info.js
@@ -14,8 +14,8 @@
import { generatePendingThreadColor } from '../shared/color-utils.js';
import type {
FarcasterConversation,
- FarcasterInboxConversation,
FarcasterConversationInvitee,
+ FarcasterInboxConversation,
} from '../shared/farcaster/farcaster-conversation-types.js';
import {
farcasterThreadIDFromConversationID,
@@ -38,8 +38,8 @@
minimallyEncodeThreadCurrentUserInfo,
} from '../types/minimally-encoded-thread-permissions-types.js';
import type { ThreadRolePermissionsBlob } from '../types/thread-permission-types.js';
-import { farcasterThreadTypes } from '../types/thread-types-enum.js';
import type { FarcasterThreadType } from '../types/thread-types-enum.js';
+import { farcasterThreadTypes } from '../types/thread-types-enum.js';
function createPermissionsInfo(
permissionsBlob: ThreadRolePermissionsBlob,
@@ -69,6 +69,7 @@
+description: string,
+createdAt: number,
+pinnedCount: number,
+ +pinnedMessageIDs: $ReadOnlyArray<string>,
+avatar: ?ClientAvatar,
+category: 'default' | 'archived' | 'request',
};
@@ -224,6 +225,7 @@
members,
roles,
currentUser,
+ pinnedMessageIDs: threadData.pinnedMessageIDs,
};
}
@@ -264,6 +266,10 @@
? ensNameForFarcasterUsername(otherUserName)
: 'anonymous';
}
+ const pinnedMessageIDs = conversation.pinnedMessages.map(
+ message => message.messageId,
+ );
+
const threadData: FarcasterThreadData = {
threadID,
isGroup: conversation.isGroup,
@@ -277,6 +283,7 @@
unread,
createdAt: conversation.createdAt,
pinnedCount: conversation.pinnedMessages.length,
+ pinnedMessageIDs,
avatar,
name,
description,
@@ -315,6 +322,7 @@
pinnedCount: threadInfo.pinnedCount ?? 0,
avatar: null,
category: 'default',
+ pinnedMessageIDs: threadInfo.pinnedMessageIDs ?? [],
};
return innerCreateFarcasterRawThreadInfo(threadData);
diff --git a/lib/utils/thread-ops-utils.js b/lib/utils/thread-ops-utils.js
--- a/lib/utils/thread-ops-utils.js
+++ b/lib/utils/thread-ops-utils.js
@@ -44,6 +44,9 @@
timestamps: rawThreadInfo.timestamps
? JSON.stringify(rawThreadInfo.timestamps)
: null,
+ pinnedMessageIDs: rawThreadInfo.pinnedMessageIDs
+ ? JSON.stringify(rawThreadInfo.pinnedMessageIDs)
+ : null,
};
}
diff --git a/lib/utils/thread-ops-utils.test.js b/lib/utils/thread-ops-utils.test.js
--- a/lib/utils/thread-ops-utils.test.js
+++ b/lib/utils/thread-ops-utils.test.js
@@ -386,6 +386,7 @@
avatar: null,
pinnedCount: 0,
timestamps: null,
+ pinnedMessageIDs: null,
};
describe('convertRawThreadInfoToClientDBThreadInfo', () => {
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Dec 6, 8:56 AM (11 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5834239
Default Alt Text
D15498.1765011396.diff (13 KB)
Attached To
Mode
D15498: [lib] Support pinning messages
Attached
Detach File
Event Timeline
Log In to Comment