diff --git a/lib/actions/message-actions.js b/lib/actions/message-actions.js --- a/lib/actions/message-actions.js +++ b/lib/actions/message-actions.js @@ -1,40 +1,6 @@ // @flow -import * as React from 'react'; - -import { - extractKeyserverIDFromIDOptional, - extractKeyserverIDFromID, - sortThreadIDsPerKeyserver, -} from '../keyserver-conn/keyserver-call-utils.js'; -import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; -import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; -import type { - FetchMessageInfosPayload, - SendMessageResult, - SendEditMessageResult, - SendReactionMessageRequest, - SimpleMessagesPayload, - SendEditMessageRequest, - FetchPinnedMessagesRequest, - FetchPinnedMessagesResult, - SearchMessagesRequest, - SearchMessagesKeyserverRequest, - SearchMessagesResponse, - FetchMessageInfosRequest, - RawMessageInfo, - MessageTruncationStatuses, - DeleteMessageRequest, - DeleteMessageResponse, -} from '../types/message-types.js'; -import { defaultNumberPerThread } from '../types/message-types.js'; import type { MediaMessageServerDBContent } from '../types/messages/media.js'; -import type { - ToggleMessagePinRequest, - ToggleMessagePinResult, -} from '../types/thread-types.js'; -import { getConfig } from '../utils/config.js'; -import { translateClientDBMessageInfoToRawMessageInfo } from '../utils/message-ops-utils.js'; const fetchMessagesBeforeCursorActionTypes = Object.freeze({ started: 'FETCH_MESSAGES_BEFORE_CURSOR_STARTED', @@ -46,41 +12,6 @@ +beforeMessageID: string, +numMessagesToFetch?: ?number, }; -const fetchMessagesBeforeCursor = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: FetchMessagesBeforeCursorInput, - ) => Promise) => - async input => { - const { threadID, beforeMessageID } = input; - - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { - [keyserverID]: { - cursors: { - [threadID]: beforeMessageID, - }, - }, - }; - - if (input.numMessagesToFetch) { - requests[keyserverID].numberPerThread = input.numMessagesToFetch; - } - - const responses = await callKeyserverEndpoint('fetch_messages', requests); - return { - threadID, - rawMessageInfos: responses[keyserverID].rawMessageInfos, - truncationStatus: responses[keyserverID].truncationStatuses[threadID], - }; - }; - -function useFetchMessagesBeforeCursor(): ( - input: FetchMessagesBeforeCursorInput, -) => Promise { - return useKeyserverCall(fetchMessagesBeforeCursor); -} export type FetchMostRecentMessagesInput = { +threadID: string, @@ -92,89 +23,12 @@ success: 'FETCH_MOST_RECENT_MESSAGES_SUCCESS', failed: 'FETCH_MOST_RECENT_MESSAGES_FAILED', }); -const fetchMostRecentMessages = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: FetchMostRecentMessagesInput, - ) => Promise) => - async input => { - const { threadID } = input; - - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { - [keyserverID]: { - cursors: { - [threadID]: null, - }, - }, - }; - - if (input.numMessagesToFetch) { - requests[keyserverID].numberPerThread = input.numMessagesToFetch; - } - - const responses = await callKeyserverEndpoint('fetch_messages', requests); - return { - threadID, - rawMessageInfos: responses[keyserverID].rawMessageInfos, - truncationStatus: responses[keyserverID].truncationStatuses[threadID], - }; - }; - -function useFetchMostRecentMessages(): ( - input: FetchMostRecentMessagesInput, -) => Promise { - return useKeyserverCall(fetchMostRecentMessages); -} const fetchSingleMostRecentMessagesFromThreadsActionTypes = Object.freeze({ started: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_STARTED', success: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_SUCCESS', failed: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_FAILED', }); -const fetchSingleMostRecentMessagesFromThreads = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((threadIDs: $ReadOnlyArray) => Promise) => - async threadIDs => { - const sortedThreadIDs = sortThreadIDsPerKeyserver(threadIDs); - - const requests: { [string]: FetchMessageInfosRequest } = {}; - for (const keyserverID in sortedThreadIDs) { - const cursors = Object.fromEntries( - sortedThreadIDs[keyserverID].map(threadID => [threadID, null]), - ); - requests[keyserverID] = { - cursors, - numberPerThread: 1, - }; - } - - const responses = await callKeyserverEndpoint('fetch_messages', requests); - let rawMessageInfos: $ReadOnlyArray = []; - let truncationStatuses: MessageTruncationStatuses = {}; - for (const keyserverID in responses) { - rawMessageInfos = rawMessageInfos.concat( - responses[keyserverID].rawMessageInfos, - ); - truncationStatuses = { - ...truncationStatuses, - ...responses[keyserverID].truncationStatuses, - }; - } - - return { - rawMessageInfos, - truncationStatuses, - }; - }; - -function useFetchSingleMostRecentMessagesFromThreads(): ( - threadIDs: $ReadOnlyArray, -) => Promise { - return useKeyserverCall(fetchSingleMostRecentMessagesFromThreads); -} export type SendTextMessageInput = { +threadID: string, @@ -188,35 +42,6 @@ success: 'SEND_TEXT_MESSAGE_SUCCESS', failed: 'SEND_TEXT_MESSAGE_FAILED', }); -const sendTextMessage = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: SendTextMessageInput) => Promise) => - async input => { - const { threadID, localID, text, sidebarCreation } = input; - let payload = { threadID, localID, text }; - if (sidebarCreation) { - payload = { ...payload, sidebarCreation }; - } - - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: payload }; - - const responses = await callKeyserverEndpoint( - 'create_text_message', - requests, - ); - return { - id: responses[keyserverID].newMessageInfo.id, - time: responses[keyserverID].newMessageInfo.time, - }; - }; - -function useSendTextMessage(): ( - input: SendTextMessageInput, -) => Promise { - return useKeyserverCall(sendTextMessage); -} const createLocalMessageActionType = 'CREATE_LOCAL_MESSAGE'; @@ -232,35 +57,6 @@ success: 'SEND_MULTIMEDIA_MESSAGE_SUCCESS', failed: 'SEND_MULTIMEDIA_MESSAGE_FAILED', }); -const sendMultimediaMessage = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: SendMultimediaMessageInput) => Promise) => - async input => { - const { threadID, localID, mediaMessageContents, sidebarCreation } = input; - let payload = { threadID, localID, mediaMessageContents }; - if (sidebarCreation) { - payload = { ...payload, sidebarCreation }; - } - - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: payload }; - - const responses = await callKeyserverEndpoint( - 'create_multimedia_message', - requests, - ); - return { - id: responses[keyserverID].newMessageInfo.id, - time: responses[keyserverID].newMessageInfo.time, - }; - }; - -function useSendMultimediaMessage(): ( - input: SendMultimediaMessageInput, -) => Promise { - return useKeyserverCall(sendMultimediaMessage); -} export type LegacySendMultimediaMessageInput = { +threadID: string, @@ -269,105 +65,17 @@ +sidebarCreation?: boolean, }; -const legacySendMultimediaMessage = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: LegacySendMultimediaMessageInput, - ) => Promise) => - async input => { - const { threadID, localID, mediaIDs, sidebarCreation } = input; - let payload = { threadID, localID, mediaIDs }; - if (sidebarCreation) { - payload = { ...payload, sidebarCreation }; - } - - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: payload }; - - const responses = await callKeyserverEndpoint( - 'create_multimedia_message', - requests, - ); - return { - id: responses[keyserverID].newMessageInfo.id, - time: responses[keyserverID].newMessageInfo.time, - }; - }; - -function useLegacySendMultimediaMessage(): ( - input: LegacySendMultimediaMessageInput, -) => Promise { - return useKeyserverCall(legacySendMultimediaMessage); -} - const sendReactionMessageActionTypes = Object.freeze({ started: 'SEND_REACTION_MESSAGE_STARTED', success: 'SEND_REACTION_MESSAGE_SUCCESS', failed: 'SEND_REACTION_MESSAGE_FAILED', }); -const sendReactionMessage = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: SendReactionMessageRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { - [keyserverID]: { - threadID: input.threadID, - localID: input.localID, - targetMessageID: input.targetMessageID, - reaction: input.reaction, - action: input.action, - }, - }; - - const responses = await callKeyserverEndpoint( - 'create_reaction_message', - requests, - ); - return { - id: responses[keyserverID].newMessageInfo.id, - time: responses[keyserverID].newMessageInfo.time, - }; - }; - -function useSendReactionMessage(): ( - input: SendReactionMessageRequest, -) => Promise { - return useKeyserverCall(sendReactionMessage); -} const sendEditMessageActionTypes = Object.freeze({ started: 'SEND_EDIT_MESSAGE_STARTED', success: 'SEND_EDIT_MESSAGE_SUCCESS', failed: 'SEND_EDIT_MESSAGE_FAILED', }); -const sendEditMessage = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: SendEditMessageRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.targetMessageID); - const requests = { - [keyserverID]: { - targetMessageID: input.targetMessageID, - text: input.text, - }, - }; - - const responses = await callKeyserverEndpoint('edit_message', requests); - - return { - newMessageInfos: responses[keyserverID].newMessageInfos, - }; - }; - -function useSendEditMessage(): ( - input: SendEditMessageRequest, -) => Promise { - return useKeyserverCall(sendEditMessage); -} const saveMessagesActionType = 'SAVE_MESSAGES'; const processMessagesActionType = 'PROCESS_MESSAGES'; @@ -378,29 +86,6 @@ success: 'FETCH_PINNED_MESSAGES_SUCCESS', failed: 'FETCH_PINNED_MESSAGES_FAILED', }); -const fetchPinnedMessages = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: FetchPinnedMessagesRequest, - ) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'fetch_pinned_messages', - requests, - ); - - return { pinnedMessages: responses[keyserverID].pinnedMessages }; - }; - -function useFetchPinnedMessages(): ( - input: FetchPinnedMessagesRequest, -) => Promise { - return useKeyserverCall(fetchPinnedMessages); -} const searchMessagesActionTypes = Object.freeze({ started: 'SEARCH_MESSAGES_STARTED', @@ -408,147 +93,32 @@ failed: 'SEARCH_MESSAGES_FAILED', }); -const searchMessages = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): (( - input: SearchMessagesKeyserverRequest, - ) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.threadID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint('search_messages', requests); - - return { - messages: responses[keyserverID].messages, - endReached: responses[keyserverID].endReached, - }; - }; - -function useSearchMessages(): ( - input: SearchMessagesRequest, -) => Promise { - const thinThreadCallback = useKeyserverCall(searchMessages); - return React.useCallback( - async (input: SearchMessagesRequest) => { - const isThreadThin = !!extractKeyserverIDFromIDOptional(input.threadID); - - if (isThreadThin) { - return await thinThreadCallback({ - query: input.query, - threadID: input.threadID, - cursor: input.messageIDCursor, - }); - } - - const { sqliteAPI } = getConfig(); - const timestampCursor = input.timestampCursor?.toString(); - const clientDBMessageInfos = await sqliteAPI.searchMessages( - input.query, - input.threadID, - timestampCursor, - input.messageIDCursor, - ); - - const messages = clientDBMessageInfos.map( - translateClientDBMessageInfoToRawMessageInfo, - ); - return { - endReached: messages.length < defaultNumberPerThread, - messages, - }; - }, - [thinThreadCallback], - ); -} - const toggleMessagePinActionTypes = Object.freeze({ started: 'TOGGLE_MESSAGE_PIN_STARTED', success: 'TOGGLE_MESSAGE_PIN_SUCCESS', failed: 'TOGGLE_MESSAGE_PIN_FAILED', }); -const toggleMessagePin = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: ToggleMessagePinRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.messageID); - const requests = { [keyserverID]: input }; - - const responses = await callKeyserverEndpoint( - 'toggle_message_pin', - requests, - ); - const response = responses[keyserverID]; - return { - newMessageInfos: response.newMessageInfos, - threadID: response.threadID, - }; - }; - -function useToggleMessagePin(): ( - input: ToggleMessagePinRequest, -) => Promise { - return useKeyserverCall(toggleMessagePin); -} const sendDeleteMessageActionTypes = Object.freeze({ started: 'SEND_DELETE_MESSAGE_STARTED', success: 'SEND_DELETE_MESSAGE_SUCCESS', failed: 'SEND_DELETE_MESSAGE_FAILED', }); -const sendDeleteMessage = - ( - callKeyserverEndpoint: CallKeyserverEndpoint, - ): ((input: DeleteMessageRequest) => Promise) => - async input => { - const keyserverID = extractKeyserverIDFromID(input.targetMessageID); - const requests = { - [keyserverID]: { - targetMessageID: input.targetMessageID, - }, - }; - - const responses = await callKeyserverEndpoint('delete_message', requests); - - return { - newMessageInfos: responses[keyserverID].newMessageInfos, - }; - }; - -function useSendDeleteMessage(): ( - input: DeleteMessageRequest, -) => Promise { - return useKeyserverCall(sendDeleteMessage); -} export { fetchMessagesBeforeCursorActionTypes, - useFetchMessagesBeforeCursor, fetchMostRecentMessagesActionTypes, - useFetchMostRecentMessages, fetchSingleMostRecentMessagesFromThreadsActionTypes, - useFetchSingleMostRecentMessagesFromThreads, sendTextMessageActionTypes, - useSendTextMessage, createLocalMessageActionType, sendMultimediaMessageActionTypes, - useSendMultimediaMessage, - useLegacySendMultimediaMessage, searchMessagesActionTypes, - useSearchMessages, sendReactionMessageActionTypes, - useSendReactionMessage, saveMessagesActionType, processMessagesActionType, messageStorePruneActionType, sendEditMessageActionTypes, - useSendEditMessage, - useFetchPinnedMessages, fetchPinnedMessageActionTypes, toggleMessagePinActionTypes, - useToggleMessagePin, sendDeleteMessageActionTypes, - useSendDeleteMessage, }; diff --git a/lib/hooks/child-threads.js b/lib/hooks/child-threads.js --- a/lib/hooks/child-threads.js +++ b/lib/hooks/child-threads.js @@ -2,10 +2,8 @@ import * as React from 'react'; -import { - fetchSingleMostRecentMessagesFromThreadsActionTypes, - useFetchSingleMostRecentMessagesFromThreads, -} from '../actions/message-actions.js'; +import { useFetchSingleMostRecentMessagesFromThreads } from './message-hooks.js'; +import { fetchSingleMostRecentMessagesFromThreadsActionTypes } from '../actions/message-actions.js'; import { useGlobalThreadSearchIndex } from '../components/global-search-index-provider.react.js'; import { type ChatThreadItem, diff --git a/lib/hooks/input-state-container-hooks.js b/lib/hooks/input-state-container-hooks.js --- a/lib/hooks/input-state-container-hooks.js +++ b/lib/hooks/input-state-container-hooks.js @@ -2,13 +2,13 @@ import * as React from 'react'; -import { useMediaMetadataReassignment } from './upload-hooks.js'; -import { useProcessBlobHolders } from '../actions/holder-actions.js'; import { useLegacySendMultimediaMessage, useSendMultimediaMessage, useSendTextMessage, -} from '../actions/message-actions.js'; +} from './message-hooks.js'; +import { useMediaMetadataReassignment } from './upload-hooks.js'; +import { useProcessBlobHolders } from '../actions/holder-actions.js'; import { useSendComposableDMOperation } from '../shared/dm-ops/process-dm-ops.js'; import { threadSpecs } from '../shared/threads/thread-specs.js'; import type { diff --git a/lib/hooks/message-hooks.js b/lib/hooks/message-hooks.js --- a/lib/hooks/message-hooks.js +++ b/lib/hooks/message-hooks.js @@ -3,6 +3,20 @@ import * as React from 'react'; import { useGetMessageAuthor } from './message-author.js'; +import type { + FetchMessagesBeforeCursorInput, + FetchMostRecentMessagesInput, + LegacySendMultimediaMessageInput, + SendMultimediaMessageInput, + SendTextMessageInput, +} from '../actions/message-actions.js'; +import { + extractKeyserverIDFromID, + extractKeyserverIDFromIDOptional, + sortThreadIDsPerKeyserver, +} from '../keyserver-conn/keyserver-call-utils.js'; +import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js'; +import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js'; import { messageInfoSelector } from '../selectors/chat-selectors.js'; import { getOldestNonLocalMessageID, @@ -11,10 +25,32 @@ import { messageSpecs } from '../shared/messages/message-specs.js'; import { messageTypes } from '../types/message-types-enum.js'; import { - type MessageInfo, + type DeleteMessageRequest, + type DeleteMessageResponse, + type FetchMessageInfosPayload, + type FetchMessageInfosRequest, + type FetchPinnedMessagesRequest, + type FetchPinnedMessagesResult, + type MessageTruncationStatuses, + type RawMessageInfo, + type SearchMessagesKeyserverRequest, + type SearchMessagesRequest, + type SearchMessagesResponse, + type SendEditMessageRequest, + type SendEditMessageResult, + type SendMessageResult, + type SendReactionMessageRequest, + type SimpleMessagesPayload, defaultNumberPerThread, + type MessageInfo, } from '../types/message-types.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; +import type { + ToggleMessagePinRequest, + ToggleMessagePinResult, +} from '../types/thread-types.js'; +import { getConfig } from '../utils/config.js'; +import { translateClientDBMessageInfoToRawMessageInfo } from '../utils/message-ops-utils.js'; import { useSelector } from '../utils/redux-utils.js'; import sleep from '../utils/sleep.js'; @@ -145,4 +181,413 @@ return messageInfoForPreview?.messageInfoForPreview; } -export { useOldestMessageServerID, useMessageInfoForPreview }; +const fetchMessagesBeforeCursor = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: FetchMessagesBeforeCursorInput, + ) => Promise) => + async input => { + const { threadID, beforeMessageID } = input; + + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { + [keyserverID]: { + cursors: { + [threadID]: beforeMessageID, + }, + }, + }; + + if (input.numMessagesToFetch) { + requests[keyserverID].numberPerThread = input.numMessagesToFetch; + } + + const responses = await callKeyserverEndpoint('fetch_messages', requests); + return { + threadID, + rawMessageInfos: responses[keyserverID].rawMessageInfos, + truncationStatus: responses[keyserverID].truncationStatuses[threadID], + }; + }; + +function useFetchMessagesBeforeCursor(): ( + input: FetchMessagesBeforeCursorInput, +) => Promise { + return useKeyserverCall(fetchMessagesBeforeCursor); +} + +const fetchMostRecentMessages = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: FetchMostRecentMessagesInput, + ) => Promise) => + async input => { + const { threadID } = input; + + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { + [keyserverID]: { + cursors: { + [threadID]: null, + }, + }, + }; + + if (input.numMessagesToFetch) { + requests[keyserverID].numberPerThread = input.numMessagesToFetch; + } + + const responses = await callKeyserverEndpoint('fetch_messages', requests); + return { + threadID, + rawMessageInfos: responses[keyserverID].rawMessageInfos, + truncationStatus: responses[keyserverID].truncationStatuses[threadID], + }; + }; + +function useFetchMostRecentMessages(): ( + input: FetchMostRecentMessagesInput, +) => Promise { + return useKeyserverCall(fetchMostRecentMessages); +} + +const fetchSingleMostRecentMessagesFromThreads = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((threadIDs: $ReadOnlyArray) => Promise) => + async threadIDs => { + const sortedThreadIDs = sortThreadIDsPerKeyserver(threadIDs); + + const requests: { [string]: FetchMessageInfosRequest } = {}; + for (const keyserverID in sortedThreadIDs) { + const cursors = Object.fromEntries( + sortedThreadIDs[keyserverID].map(threadID => [threadID, null]), + ); + requests[keyserverID] = { + cursors, + numberPerThread: 1, + }; + } + + const responses = await callKeyserverEndpoint('fetch_messages', requests); + let rawMessageInfos: $ReadOnlyArray = []; + let truncationStatuses: MessageTruncationStatuses = {}; + for (const keyserverID in responses) { + rawMessageInfos = rawMessageInfos.concat( + responses[keyserverID].rawMessageInfos, + ); + truncationStatuses = { + ...truncationStatuses, + ...responses[keyserverID].truncationStatuses, + }; + } + + return { + rawMessageInfos, + truncationStatuses, + }; + }; + +function useFetchSingleMostRecentMessagesFromThreads(): ( + threadIDs: $ReadOnlyArray, +) => Promise { + return useKeyserverCall(fetchSingleMostRecentMessagesFromThreads); +} + +const sendTextMessage = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: SendTextMessageInput) => Promise) => + async input => { + const { threadID, localID, text, sidebarCreation } = input; + let payload = { threadID, localID, text }; + if (sidebarCreation) { + payload = { ...payload, sidebarCreation }; + } + + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: payload }; + + const responses = await callKeyserverEndpoint( + 'create_text_message', + requests, + ); + return { + id: responses[keyserverID].newMessageInfo.id, + time: responses[keyserverID].newMessageInfo.time, + }; + }; + +function useSendTextMessage(): ( + input: SendTextMessageInput, +) => Promise { + return useKeyserverCall(sendTextMessage); +} + +const sendMultimediaMessage = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: SendMultimediaMessageInput) => Promise) => + async input => { + const { threadID, localID, mediaMessageContents, sidebarCreation } = input; + let payload = { threadID, localID, mediaMessageContents }; + if (sidebarCreation) { + payload = { ...payload, sidebarCreation }; + } + + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: payload }; + + const responses = await callKeyserverEndpoint( + 'create_multimedia_message', + requests, + ); + return { + id: responses[keyserverID].newMessageInfo.id, + time: responses[keyserverID].newMessageInfo.time, + }; + }; + +function useSendMultimediaMessage(): ( + input: SendMultimediaMessageInput, +) => Promise { + return useKeyserverCall(sendMultimediaMessage); +} + +const legacySendMultimediaMessage = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: LegacySendMultimediaMessageInput, + ) => Promise) => + async input => { + const { threadID, localID, mediaIDs, sidebarCreation } = input; + let payload = { threadID, localID, mediaIDs }; + if (sidebarCreation) { + payload = { ...payload, sidebarCreation }; + } + + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: payload }; + + const responses = await callKeyserverEndpoint( + 'create_multimedia_message', + requests, + ); + return { + id: responses[keyserverID].newMessageInfo.id, + time: responses[keyserverID].newMessageInfo.time, + }; + }; + +function useLegacySendMultimediaMessage(): ( + input: LegacySendMultimediaMessageInput, +) => Promise { + return useKeyserverCall(legacySendMultimediaMessage); +} + +const sendReactionMessage = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: SendReactionMessageRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { + [keyserverID]: { + threadID: input.threadID, + localID: input.localID, + targetMessageID: input.targetMessageID, + reaction: input.reaction, + action: input.action, + }, + }; + + const responses = await callKeyserverEndpoint( + 'create_reaction_message', + requests, + ); + return { + id: responses[keyserverID].newMessageInfo.id, + time: responses[keyserverID].newMessageInfo.time, + }; + }; + +function useSendReactionMessage(): ( + input: SendReactionMessageRequest, +) => Promise { + return useKeyserverCall(sendReactionMessage); +} + +const sendEditMessage = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: SendEditMessageRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.targetMessageID); + const requests = { + [keyserverID]: { + targetMessageID: input.targetMessageID, + text: input.text, + }, + }; + + const responses = await callKeyserverEndpoint('edit_message', requests); + + return { + newMessageInfos: responses[keyserverID].newMessageInfos, + }; + }; + +function useSendEditMessage(): ( + input: SendEditMessageRequest, +) => Promise { + return useKeyserverCall(sendEditMessage); +} + +const fetchPinnedMessages = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: FetchPinnedMessagesRequest, + ) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'fetch_pinned_messages', + requests, + ); + + return { pinnedMessages: responses[keyserverID].pinnedMessages }; + }; + +function useFetchPinnedMessages(): ( + input: FetchPinnedMessagesRequest, +) => Promise { + return useKeyserverCall(fetchPinnedMessages); +} + +const searchMessages = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): (( + input: SearchMessagesKeyserverRequest, + ) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.threadID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint('search_messages', requests); + + return { + messages: responses[keyserverID].messages, + endReached: responses[keyserverID].endReached, + }; + }; + +function useSearchMessages(): ( + input: SearchMessagesRequest, +) => Promise { + const thinThreadCallback = useKeyserverCall(searchMessages); + return React.useCallback( + async (input: SearchMessagesRequest) => { + const isThreadThin = !!extractKeyserverIDFromIDOptional(input.threadID); + + if (isThreadThin) { + return await thinThreadCallback({ + query: input.query, + threadID: input.threadID, + cursor: input.messageIDCursor, + }); + } + + const { sqliteAPI } = getConfig(); + const timestampCursor = input.timestampCursor?.toString(); + const clientDBMessageInfos = await sqliteAPI.searchMessages( + input.query, + input.threadID, + timestampCursor, + input.messageIDCursor, + ); + + const messages = clientDBMessageInfos.map( + translateClientDBMessageInfoToRawMessageInfo, + ); + return { + endReached: messages.length < defaultNumberPerThread, + messages, + }; + }, + [thinThreadCallback], + ); +} + +const toggleMessagePin = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: ToggleMessagePinRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.messageID); + const requests = { [keyserverID]: input }; + + const responses = await callKeyserverEndpoint( + 'toggle_message_pin', + requests, + ); + const response = responses[keyserverID]; + return { + newMessageInfos: response.newMessageInfos, + threadID: response.threadID, + }; + }; + +function useToggleMessagePin(): ( + input: ToggleMessagePinRequest, +) => Promise { + return useKeyserverCall(toggleMessagePin); +} + +const sendDeleteMessage = + ( + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: DeleteMessageRequest) => Promise) => + async input => { + const keyserverID = extractKeyserverIDFromID(input.targetMessageID); + const requests = { + [keyserverID]: { + targetMessageID: input.targetMessageID, + }, + }; + + const responses = await callKeyserverEndpoint('delete_message', requests); + + return { + newMessageInfos: responses[keyserverID].newMessageInfos, + }; + }; + +function useSendDeleteMessage(): ( + input: DeleteMessageRequest, +) => Promise { + return useKeyserverCall(sendDeleteMessage); +} + +export { + useOldestMessageServerID, + useMessageInfoForPreview, + useSendDeleteMessage, + useToggleMessagePin, + useSearchMessages, + useFetchPinnedMessages, + useSendEditMessage, + useSendReactionMessage, + useLegacySendMultimediaMessage, + useSendMultimediaMessage, + useSendTextMessage, + useFetchSingleMostRecentMessagesFromThreads, + useFetchMostRecentMessages, + useFetchMessagesBeforeCursor, +}; diff --git a/lib/shared/edit-messages-utils.js b/lib/shared/edit-messages-utils.js --- a/lib/shared/edit-messages-utils.js +++ b/lib/shared/edit-messages-utils.js @@ -10,10 +10,8 @@ } from './dm-ops/dm-op-types.js'; import { useProcessAndSendDMOperation } from './dm-ops/process-dm-ops.js'; import { threadIsPending, useThreadHasPermission } from './thread-utils.js'; -import { - sendEditMessageActionTypes, - useSendEditMessage, -} from '../actions/message-actions.js'; +import { sendEditMessageActionTypes } from '../actions/message-actions.js'; +import { useSendEditMessage } from '../hooks/message-hooks.js'; import { type DMSendEditMessageOperation } from '../types/dm-ops.js'; import type { ComposableMessageInfo, diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js --- a/lib/shared/message-utils.js +++ b/lib/shared/message-utils.js @@ -13,11 +13,13 @@ import { fetchMessagesBeforeCursorActionTypes, fetchMostRecentMessagesActionTypes, - useFetchMessagesBeforeCursor, - useFetchMostRecentMessages, } from '../actions/message-actions.js'; import { useStringForUser } from '../hooks/ens-cache.js'; -import { useOldestMessageServerID } from '../hooks/message-hooks.js'; +import { + useFetchMessagesBeforeCursor, + useFetchMostRecentMessages, + useOldestMessageServerID, +} from '../hooks/message-hooks.js'; import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; import { contentStringForMediaArray } from '../media/media-utils.js'; import { registerFetchKey } from '../reducers/loading-reducer.js'; diff --git a/lib/shared/search-utils.js b/lib/shared/search-utils.js --- a/lib/shared/search-utils.js +++ b/lib/shared/search-utils.js @@ -10,16 +10,14 @@ userHasDeviceList, } from './thread-utils.js'; import { threadTypeIsSidebar } from './threads/thread-specs.js'; -import { - searchMessagesActionTypes, - useSearchMessages as useSearchMessagesAction, -} from '../actions/message-actions.js'; +import { searchMessagesActionTypes } from '../actions/message-actions.js'; import { searchUsers, searchUsersActionTypes, } from '../actions/user-actions.js'; import { ENSCacheContext } from '../components/ens-cache-provider.react.js'; import genesis from '../facts/genesis.js'; +import { useSearchMessages as useSearchMessagesAction } from '../hooks/message-hooks.js'; import { useIdentitySearch } from '../identity-search/identity-search-context.js'; import { useLegacyAshoatKeyserverCall } from '../keyserver-conn/legacy-keyserver-call.js'; import { decodeThreadRolePermissionsBitmaskArray } from '../permissions/minimally-encoded-thread-permissions.js'; diff --git a/lib/shared/watch-thread-utils.js b/lib/shared/watch-thread-utils.js --- a/lib/shared/watch-thread-utils.js +++ b/lib/shared/watch-thread-utils.js @@ -4,10 +4,8 @@ import { useIsThreadInChatList } from './thread-utils.js'; import threadWatcher from './thread-watcher.js'; -import { - fetchMostRecentMessagesActionTypes, - useFetchMostRecentMessages, -} from '../actions/message-actions.js'; +import { fetchMostRecentMessagesActionTypes } from '../actions/message-actions.js'; +import { useFetchMostRecentMessages } from '../hooks/message-hooks.js'; import type { ThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js'; import { useDispatchActionPromise } from '../utils/redux-promise-utils.js'; diff --git a/lib/utils/delete-message-utils.js b/lib/utils/delete-message-utils.js --- a/lib/utils/delete-message-utils.js +++ b/lib/utils/delete-message-utils.js @@ -6,10 +6,8 @@ import { useDispatchActionPromise } from './redux-promise-utils.js'; import { useSelector } from './redux-utils.js'; -import { - sendDeleteMessageActionTypes, - useSendDeleteMessage, -} from '../actions/message-actions.js'; +import { sendDeleteMessageActionTypes } from '../actions/message-actions.js'; +import { useSendDeleteMessage } from '../hooks/message-hooks.js'; import { dmOperationSpecificationTypes, type OutboundDMOperationSpecification, diff --git a/native/chat/pinned-messages-screen.react.js b/native/chat/pinned-messages-screen.react.js --- a/native/chat/pinned-messages-screen.react.js +++ b/native/chat/pinned-messages-screen.react.js @@ -5,7 +5,7 @@ import { View } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; -import { useFetchPinnedMessages } from 'lib/actions/message-actions.js'; +import { useFetchPinnedMessages } from 'lib/hooks/message-hooks.js'; import { type ChatMessageInfoItem, messageListData, diff --git a/native/chat/reaction-message-utils.js b/native/chat/reaction-message-utils.js --- a/native/chat/reaction-message-utils.js +++ b/native/chat/reaction-message-utils.js @@ -4,10 +4,8 @@ import * as React from 'react'; import uuid from 'uuid'; -import { - useSendReactionMessage, - sendReactionMessageActionTypes, -} from 'lib/actions/message-actions.js'; +import { sendReactionMessageActionTypes } from 'lib/actions/message-actions.js'; +import { useSendReactionMessage } from 'lib/hooks/message-hooks.js'; import type { ReactionInfo } from 'lib/selectors/chat-selectors.js'; import { dmOperationSpecificationTypes, diff --git a/native/chat/toggle-pin-modal.react.js b/native/chat/toggle-pin-modal.react.js --- a/native/chat/toggle-pin-modal.react.js +++ b/native/chat/toggle-pin-modal.react.js @@ -4,10 +4,8 @@ import * as React from 'react'; import { Text, View } from 'react-native'; -import { - toggleMessagePinActionTypes, - useToggleMessagePin, -} from 'lib/actions/message-actions.js'; +import { toggleMessagePinActionTypes } from 'lib/actions/message-actions.js'; +import { useToggleMessagePin } from 'lib/hooks/message-hooks.js'; import type { RawMessageInfo } from 'lib/types/message-types.js'; import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; diff --git a/web/chat/reaction-message-utils.js b/web/chat/reaction-message-utils.js --- a/web/chat/reaction-message-utils.js +++ b/web/chat/reaction-message-utils.js @@ -4,11 +4,9 @@ import * as React from 'react'; import uuid from 'uuid'; -import { - useSendReactionMessage, - sendReactionMessageActionTypes, -} from 'lib/actions/message-actions.js'; +import { sendReactionMessageActionTypes } from 'lib/actions/message-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useSendReactionMessage } from 'lib/hooks/message-hooks.js'; import type { ReactionInfo } from 'lib/selectors/chat-selectors'; import { dmOperationSpecificationTypes, diff --git a/web/modals/chat/pinned-messages-modal.react.js b/web/modals/chat/pinned-messages-modal.react.js --- a/web/modals/chat/pinned-messages-modal.react.js +++ b/web/modals/chat/pinned-messages-modal.react.js @@ -2,11 +2,9 @@ import * as React from 'react'; -import { - fetchPinnedMessageActionTypes, - useFetchPinnedMessages, -} from 'lib/actions/message-actions.js'; +import { fetchPinnedMessageActionTypes } from 'lib/actions/message-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useFetchPinnedMessages } from 'lib/hooks/message-hooks.js'; import { type ChatMessageInfoItem, messageListData, diff --git a/web/modals/chat/toggle-pin-modal.react.js b/web/modals/chat/toggle-pin-modal.react.js --- a/web/modals/chat/toggle-pin-modal.react.js +++ b/web/modals/chat/toggle-pin-modal.react.js @@ -3,11 +3,9 @@ import invariant from 'invariant'; import * as React from 'react'; -import { - toggleMessagePinActionTypes, - useToggleMessagePin, -} from 'lib/actions/message-actions.js'; +import { toggleMessagePinActionTypes } from 'lib/actions/message-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; +import { useToggleMessagePin } from 'lib/hooks/message-hooks.js'; import type { ChatMessageInfoItem } from 'lib/selectors/chat-selectors.js'; import { chatMessageItemEngagementTargetMessageInfo } from 'lib/shared/chat-message-item-utils.js'; import { modifyItemForResultScreen } from 'lib/shared/message-utils.js';