diff --git a/lib/components/farcaster-data-handler.react.js b/lib/components/farcaster-data-handler.react.js --- a/lib/components/farcaster-data-handler.react.js +++ b/lib/components/farcaster-data-handler.react.js @@ -241,30 +241,42 @@ const syncFarcasterConversations = useFarcasterConversationsSync(); const currentUserSupportsDCs = useCurrentUserSupportsDCs(); - const [shouldSync, setShouldSync] = React.useState(true); + const [syncType, setSyncType] = React.useState<'none' | 'partial' | 'full'>( + 'partial', + ); const tunnelbroker = useTunnelbroker(); + + const prevSupport = React.useRef(currentUserSupportsDCs); + React.useEffect(() => { + if (currentUserSupportsDCs && !prevSupport.current) { + setSyncType('full'); + } + prevSupport.current = currentUserSupportsDCs; + }, [currentUserSupportsDCs]); + React.useEffect(() => { if ( !currentUserSupportsDCs || - !shouldSync || + syncType === 'none' || !tunnelbroker.socketState.connected ) { return; } - setShouldSync(false); - void syncFarcasterConversations(); + setSyncType('none'); + const limit = syncType === 'partial' ? 20 : Number.POSITIVE_INFINITY; + void syncFarcasterConversations(limit); }, [ currentUserSupportsDCs, - shouldSync, + syncType, syncFarcasterConversations, tunnelbroker.socketState.connected, ]); React.useEffect(() => { - if (!currentUserSupportsDCs && !shouldSync) { - setShouldSync(true); + if (!currentUserSupportsDCs && syncType === 'none') { + setSyncType('full'); } - }, [currentUserSupportsDCs, shouldSync]); + }, [currentUserSupportsDCs, syncType]); return farcasterDataHandler; } 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 @@ -85,13 +85,23 @@ messages: t.list(farcasterMessageValidator), }); +type FetchFarcasterMessageCursor = { + +cursor?: string, +}; +const fetchFarcasterMessageCursorValidator: TInterface = + tShapeInexact({ + cursor: t.maybe(t.String), + }); + export type FetchFarcasterMessageResult = { +result: FetchFarcasterMessageResultData, + +next?: FetchFarcasterMessageCursor, ... }; const fetchFarcasterMessageResultValidator: TInterface = tShapeInexact({ result: fetchFarcasterMessageResultDataValidator, + next: t.maybe(fetchFarcasterMessageCursorValidator), }); function useFetchFarcasterMessages(): ( 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 @@ -20,11 +20,12 @@ import { useDispatch } from '../../utils/redux-utils.js'; import { useSendDMOperationUtils } from '../dm-ops/dm-op-utils.js'; -function useFarcasterConversationsSync(): () => Promise { +function useFarcasterConversationsSync(): (limit: number) => Promise { const [fullInbox, setFullInbox] = React.useState(false); const [conversations, setConversations] = React.useState< $ReadOnlyArray, >([]); + const [messagesNumberLimit, setMessagesNumberLimit] = React.useState(20); const fetchFarcasterInbox = useFetchFarcasterInbox(); const fetchFarcasterConversation = useFetchFarcasterConversation(); @@ -109,23 +110,49 @@ for (const farcasterConversation of farcasterConversations) { try { - const messagesResult = await fetchFarcasterMessages({ - conversationId: farcasterConversation.conversationId, - limit: 30, - }); - if (messagesResult) { - const farcasterMessages = messagesResult.result.messages; - const rawMessageInfos = farcasterMessages.flatMap( - convertFarcasterMessageToCommMessages, + let cursor: ?string = null; + let totalMessagesFetched = 0; + + do { + const batchLimit = Math.min( + 20, + messagesNumberLimit - totalMessagesFetched, ); - dispatch({ - type: processFarcasterOpsActionType, - payload: { - rawMessageInfos, - updateInfos: [], - }, - }); - } + + if (batchLimit <= 0) { + break; + } + + const messagesInput = { + conversationId: farcasterConversation.conversationId, + limit: batchLimit, + ...(cursor ? { cursor } : {}), + }; + + const messagesResult = await fetchFarcasterMessages(messagesInput); + + if (messagesResult) { + const farcasterMessages = messagesResult.result.messages; + const rawMessageInfos = farcasterMessages.flatMap( + convertFarcasterMessageToCommMessages, + ); + + if (rawMessageInfos.length > 0) { + dispatch({ + type: processFarcasterOpsActionType, + payload: { + rawMessageInfos, + updateInfos: [], + }, + }); + totalMessagesFetched += farcasterMessages.length; + } + + cursor = messagesResult.next?.cursor; + } else { + cursor = null; + } + } while (cursor && totalMessagesFetched < messagesNumberLimit); } catch (e) { console.error( `Failed fetching messages for ${farcasterConversation.conversationId}:`, @@ -144,14 +171,19 @@ fetchFarcasterMessages, fullInbox, inProgress, + messagesNumberLimit, sendFarcasterTextMessage, utils, ]); - return React.useCallback(async () => { - setFullInbox(false); - void fetchInboxes(null); - }, [fetchInboxes]); + return React.useCallback( + async (limit: number) => { + setMessagesNumberLimit(limit); + setFullInbox(false); + void fetchInboxes(null); + }, + [fetchInboxes], + ); } export { useFarcasterConversationsSync }; diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js --- a/lib/tunnelbroker/use-peer-to-peer-message-handler.js +++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js @@ -245,7 +245,7 @@ if (!userActionMessage.hasDCsToken) { clearFarcasterThreads(); } else { - await syncFarcasterConversations(); + await syncFarcasterConversations(Number.POSITIVE_INFINITY); } } else { console.warn( diff --git a/native/profile/profile-screen.react.js b/native/profile/profile-screen.react.js --- a/native/profile/profile-screen.react.js +++ b/native/profile/profile-screen.react.js @@ -186,7 +186,7 @@ +onCreateDMThread: () => Promise, +currentUserFID: ?string, +usingRestoreFlow: boolean, - +farcasterConversationsSync: () => Promise, + +farcasterConversationsSync: (limit: number) => Promise, }; class ProfileScreen extends React.PureComponent { @@ -562,7 +562,7 @@ }; onPressFarcasterConversationsSync = () => { - void this.props.farcasterConversationsSync(); + void this.props.farcasterConversationsSync(Number.POSITIVE_INFINITY); }; onPressDebugLogs = () => { diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js --- a/web/settings/account-settings.react.js +++ b/web/settings/account-settings.react.js @@ -183,6 +183,9 @@ ); const farcasterConversationsSync = useFarcasterConversationsSync(); + const syncConversations = React.useCallback(() => { + return farcasterConversationsSync(Number.POSITIVE_INFINITY); + }, [farcasterConversationsSync]); if (!currentUserInfo || currentUserInfo.anonymous) { return null; @@ -291,7 +294,7 @@
  • Farcaster DCs integration -