diff --git a/lib/actions/activity-actions.js b/lib/actions/activity-actions.js --- a/lib/actions/activity-actions.js +++ b/lib/actions/activity-actions.js @@ -7,7 +7,7 @@ SetThreadUnreadStatusRequest, SetThreadUnreadStatusResult, } from '../types/activity-types'; -import type { FetchJSON } from '../utils/fetch-json'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; const updateActivityActionTypes = Object.freeze({ started: 'UPDATE_ACTIVITY_STARTED', @@ -15,11 +15,11 @@ failed: 'UPDATE_ACTIVITY_FAILED', }); const updateActivity = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( activityUpdates: $ReadOnlyArray, ) => Promise) => async activityUpdates => { - const response = await fetchJSON('update_activity', { + const response = await callServerEndpoint('update_activity', { updates: activityUpdates, }); return { @@ -36,11 +36,11 @@ failed: 'SET_THREAD_UNREAD_STATUS_FAILED', }); const setThreadUnreadStatus = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: SetThreadUnreadStatusRequest, ) => Promise) => async request => { - const response: SetThreadUnreadStatusResult = await fetchJSON( + const response: SetThreadUnreadStatusResult = await callServerEndpoint( 'set_thread_unread_status', request, ); diff --git a/lib/actions/device-actions.js b/lib/actions/device-actions.js --- a/lib/actions/device-actions.js +++ b/lib/actions/device-actions.js @@ -1,7 +1,7 @@ // @flow +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import { getConfig } from '../utils/config'; -import type { FetchJSON } from '../utils/fetch-json'; const setDeviceTokenActionTypes = Object.freeze({ started: 'SET_DEVICE_TOKEN_STARTED', @@ -9,9 +9,9 @@ failed: 'SET_DEVICE_TOKEN_FAILED', }); const setDeviceToken = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((deviceToken: ?string) => Promise) => async deviceToken => { - await fetchJSON('update_device_token', { + await callServerEndpoint('update_device_token', { deviceToken, platformDetails: getConfig().platformDetails, }); diff --git a/lib/actions/entry-actions.js b/lib/actions/entry-actions.js --- a/lib/actions/entry-actions.js +++ b/lib/actions/entry-actions.js @@ -16,8 +16,8 @@ CalendarQueryUpdateResult, } from '../types/entry-types'; import type { HistoryRevisionInfo } from '../types/history-types'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import { dateFromString } from '../utils/date-utils'; -import type { FetchJSON } from '../utils/fetch-json'; const fetchEntriesActionTypes = Object.freeze({ started: 'FETCH_ENTRIES_STARTED', @@ -25,11 +25,11 @@ failed: 'FETCH_ENTRIES_FAILED', }); const fetchEntries = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( calendarQuery: CalendarQuery, ) => Promise) => async calendarQuery => { - const response = await fetchJSON('fetch_entries', calendarQuery); + const response = await callServerEndpoint('fetch_entries', calendarQuery); return { rawEntryInfos: response.rawEntryInfos, }; @@ -41,7 +41,7 @@ failed: 'UPDATE_CALENDAR_QUERY_FAILED', }); const updateCalendarQuery = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( calendarQuery: CalendarQuery, reduxAlreadyUpdated?: boolean, @@ -49,7 +49,10 @@ calendarQuery, reduxAlreadyUpdated = false, ) => { - const response = await fetchJSON('update_calendar_query', calendarQuery); + const response = await callServerEndpoint( + 'update_calendar_query', + calendarQuery, + ); const { rawEntryInfos, deletedEntryIDs } = response; return { rawEntryInfos, @@ -87,11 +90,11 @@ failed: 'CREATE_ENTRY_FAILED', }); const createEntry = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: CreateEntryInfo, ) => Promise) => async request => { - const result = await fetchJSON('create_entry', request); + const result = await callServerEndpoint('create_entry', request); return { entryID: result.entryID, newMessageInfos: result.newMessageInfos, @@ -108,9 +111,9 @@ }); const concurrentModificationResetActionType = 'CONCURRENT_MODIFICATION_RESET'; const saveEntry = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((request: SaveEntryInfo) => Promise) => async request => { - const result = await fetchJSON('update_entry', request); + const result = await callServerEndpoint('update_entry', request); return { entryID: result.entryID, newMessageInfos: result.newMessageInfos, @@ -124,9 +127,9 @@ failed: 'DELETE_ENTRY_FAILED', }); const deleteEntry = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((info: DeleteEntryInfo) => Promise) => async info => { - const response = await fetchJSON('delete_entry', { + const response = await callServerEndpoint('delete_entry', { ...info, timestamp: Date.now(), }); @@ -143,11 +146,13 @@ failed: 'FETCH_REVISIONS_FOR_ENTRY_FAILED', }); const fetchRevisionsForEntry = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( entryID: string, ) => Promise<$ReadOnlyArray>) => async entryID => { - const response = await fetchJSON('fetch_entry_revisions', { id: entryID }); + const response = await callServerEndpoint('fetch_entry_revisions', { + id: entryID, + }); return response.result; }; @@ -157,9 +162,9 @@ failed: 'RESTORE_ENTRY_FAILED', }); const restoreEntry = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((info: RestoreEntryInfo) => Promise) => async info => { - const response = await fetchJSON('restore_entry', { + const response = await callServerEndpoint('restore_entry', { ...info, timestamp: Date.now(), }); 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 @@ -8,7 +8,10 @@ SimpleMessagesPayload, } from '../types/message-types'; import type { MediaMessageServerDBContent } from '../types/messages/media.js'; -import type { FetchJSON, FetchResultInfo } from '../utils/fetch-json'; +import type { + CallServerEndpoint, + CallServerEndpointResultInfo, +} from '../utils/call-server-endpoint'; const fetchMessagesBeforeCursorActionTypes = Object.freeze({ started: 'FETCH_MESSAGES_BEFORE_CURSOR_STARTED', @@ -16,7 +19,7 @@ failed: 'FETCH_MESSAGES_BEFORE_CURSOR_FAILED', }); const fetchMessagesBeforeCursor = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, beforeMessageID: string, @@ -24,7 +27,7 @@ threadID, beforeMessageID, ) => { - const response = await fetchJSON('fetch_messages', { + const response = await callServerEndpoint('fetch_messages', { cursors: { [threadID]: beforeMessageID, }, @@ -42,11 +45,11 @@ failed: 'FETCH_MOST_RECENT_MESSAGES_FAILED', }); const fetchMostRecentMessages = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, ) => Promise) => async threadID => { - const response = await fetchJSON('fetch_messages', { + const response = await callServerEndpoint('fetch_messages', { cursors: { [threadID]: null, }, @@ -64,14 +67,14 @@ failed: 'FETCH_SINGLE_MOST_RECENT_MESSAGES_FROM_THREADS_FAILED', }); const fetchSingleMostRecentMessagesFromThreads = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadIDs: $ReadOnlyArray, ) => Promise) => async threadIDs => { const cursors = Object.fromEntries( threadIDs.map(threadID => [threadID, null]), ); - const response = await fetchJSON('fetch_messages', { + const response = await callServerEndpoint('fetch_messages', { cursors, numberPerThread: 1, }); @@ -87,17 +90,17 @@ failed: 'SEND_TEXT_MESSAGE_FAILED', }); const sendTextMessage = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, localID: string, text: string, ) => Promise) => async (threadID, localID, text) => { let resultInfo; - const getResultInfo = (passedResultInfo: FetchResultInfo) => { + const getResultInfo = (passedResultInfo: CallServerEndpointResultInfo) => { resultInfo = passedResultInfo; }; - const response = await fetchJSON( + const response = await callServerEndpoint( 'create_text_message', { threadID, @@ -109,7 +112,7 @@ const resultInterface = resultInfo?.interface; invariant( resultInterface, - 'getResultInfo not called before fetchJSON resolves', + 'getResultInfo not called before callServerEndpoint resolves', ); return { id: response.newMessageInfo.id, @@ -126,7 +129,7 @@ failed: 'SEND_MULTIMEDIA_MESSAGE_FAILED', }); const sendMultimediaMessage = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, localID: string, @@ -137,10 +140,10 @@ mediaMessageContents, ) => { let resultInfo; - const getResultInfo = (passedResultInfo: FetchResultInfo) => { + const getResultInfo = (passedResultInfo: CallServerEndpointResultInfo) => { resultInfo = passedResultInfo; }; - const response = await fetchJSON( + const response = await callServerEndpoint( 'create_multimedia_message', { threadID, @@ -152,7 +155,7 @@ const resultInterface = resultInfo?.interface; invariant( resultInterface, - 'getResultInfo not called before fetchJSON resolves', + 'getResultInfo not called before callServerEndpoint resolves', ); return { id: response.newMessageInfo.id, @@ -162,17 +165,17 @@ }; const legacySendMultimediaMessage = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, localID: string, mediaIDs: $ReadOnlyArray, ) => Promise) => async (threadID, localID, mediaIDs) => { let resultInfo; - const getResultInfo = (passedResultInfo: FetchResultInfo) => { + const getResultInfo = (passedResultInfo: CallServerEndpointResultInfo) => { resultInfo = passedResultInfo; }; - const response = await fetchJSON( + const response = await callServerEndpoint( 'create_multimedia_message', { threadID, @@ -184,7 +187,7 @@ const resultInterface = resultInfo?.interface; invariant( resultInterface, - 'getResultInfo not called before fetchJSON resolves', + 'getResultInfo not called before callServerEndpoint resolves', ); return { id: response.newMessageInfo.id, diff --git a/lib/actions/relationship-actions.js b/lib/actions/relationship-actions.js --- a/lib/actions/relationship-actions.js +++ b/lib/actions/relationship-actions.js @@ -4,8 +4,8 @@ RelationshipRequest, RelationshipErrors, } from '../types/relationship-types'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import { ServerError } from '../utils/errors'; -import type { FetchJSON } from '../utils/fetch-json'; const updateRelationshipsActionTypes = Object.freeze({ started: 'UPDATE_RELATIONSHIPS_STARTED', @@ -13,11 +13,11 @@ failed: 'UPDATE_RELATIONSHIPS_FAILED', }); const updateRelationships = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: RelationshipRequest, ) => Promise) => async request => { - const errors = await fetchJSON('update_relationships', request); + const errors = await callServerEndpoint('update_relationships', request); const { invalid_user, already_friends, user_blocked } = errors; if (invalid_user) { diff --git a/lib/actions/report-actions.js b/lib/actions/report-actions.js --- a/lib/actions/report-actions.js +++ b/lib/actions/report-actions.js @@ -4,20 +4,24 @@ ClientReportCreationRequest, ReportCreationResponse, } from '../types/report-types'; -import type { FetchJSON } from '../utils/fetch-json'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; const sendReportActionTypes = Object.freeze({ started: 'SEND_REPORT_STARTED', success: 'SEND_REPORT_SUCCESS', failed: 'SEND_REPORT_FAILED', }); -const fetchJSONOptions = { timeout: 60000 }; +const callServerEndpointOptions = { timeout: 60000 }; const sendReport = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: ClientReportCreationRequest, ) => Promise) => async request => { - const response = await fetchJSON('create_report', request, fetchJSONOptions); + const response = await callServerEndpoint( + 'create_report', + request, + callServerEndpointOptions, + ); return { id: response.id }; }; @@ -27,11 +31,15 @@ failed: 'SEND_REPORTS_FAILED', }); const sendReports = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( reports: $ReadOnlyArray, ) => Promise) => async reports => { - await fetchJSON('create_reports', { reports }, fetchJSONOptions); + await callServerEndpoint( + 'create_reports', + { reports }, + callServerEndpointOptions, + ); }; const queueReportsActionType = 'QUEUE_REPORTS'; diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js --- a/lib/actions/thread-actions.js +++ b/lib/actions/thread-actions.js @@ -11,7 +11,7 @@ ClientThreadJoinRequest, ThreadJoinPayload, } from '../types/thread-types'; -import type { FetchJSON } from '../utils/fetch-json'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import { values } from '../utils/objects'; const deleteThreadActionTypes = Object.freeze({ @@ -20,7 +20,7 @@ failed: 'DELETE_THREAD_FAILED', }); const deleteThread = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, currentAccountPassword: string, @@ -28,7 +28,7 @@ threadID, currentAccountPassword, ) => { - const response = await fetchJSON('delete_thread', { + const response = await callServerEndpoint('delete_thread', { threadID, accountPassword: currentAccountPassword, }); @@ -43,11 +43,11 @@ failed: 'CHANGE_THREAD_SETTINGS_FAILED', }); const changeThreadSettings = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: UpdateThreadRequest, ) => Promise) => async request => { - const response = await fetchJSON('update_thread', request); + const response = await callServerEndpoint('update_thread', request); invariant( Object.keys(request.changes).length > 0, 'No changes provided to changeThreadSettings!', @@ -65,12 +65,12 @@ failed: 'REMOVE_USERS_FROM_THREAD_FAILED', }); const removeUsersFromThread = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, memberIDs: $ReadOnlyArray, ) => Promise) => async (threadID, memberIDs) => { - const response = await fetchJSON('remove_members', { + const response = await callServerEndpoint('remove_members', { threadID, memberIDs, }); @@ -87,7 +87,7 @@ failed: 'CHANGE_THREAD_MEMBER_ROLES_FAILED', }); const changeThreadMemberRoles = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( threadID: string, memberIDs: $ReadOnlyArray, @@ -97,7 +97,7 @@ memberIDs, newRole, ) => { - const response = await fetchJSON('update_role', { + const response = await callServerEndpoint('update_role', { threadID, memberIDs, role: newRole, @@ -115,11 +115,11 @@ failed: 'NEW_THREAD_FAILED', }); const newThread = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: ClientNewThreadRequest, ) => Promise) => async request => { - const response = await fetchJSON('create_thread', request); + const response = await callServerEndpoint('create_thread', request); return { newThreadID: response.newThreadID, updatesResult: response.updatesResult, @@ -134,11 +134,11 @@ failed: 'JOIN_THREAD_FAILED', }); const joinThread = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( request: ClientThreadJoinRequest, ) => Promise) => async request => { - const response = await fetchJSON('join_thread', request); + const response = await callServerEndpoint('join_thread', request); const userInfos = values(response.userInfos); return { updatesResult: response.updatesResult, @@ -154,9 +154,9 @@ failed: 'LEAVE_THREAD_FAILED', }); const leaveThread = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((threadID: string) => Promise) => async threadID => { - const response = await fetchJSON('leave_thread', { threadID }); + const response = await callServerEndpoint('leave_thread', { threadID }); return { updatesResult: response.updatesResult, }; diff --git a/lib/actions/upload-actions.js b/lib/actions/upload-actions.js --- a/lib/actions/upload-actions.js +++ b/lib/actions/upload-actions.js @@ -2,7 +2,7 @@ import type { Shape } from '../types/core'; import type { UploadMultimediaResult, Dimensions } from '../types/media-types'; -import type { FetchJSON } from '../utils/fetch-json'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import type { UploadBlob } from '../utils/upload-blob'; export type MultimediaUploadCallbacks = Shape<{ @@ -13,7 +13,7 @@ export type MultimediaUploadExtras = Shape<{ ...Dimensions, loop: boolean }>; const uploadMultimedia = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( multimedia: Object, extras: MultimediaUploadExtras, @@ -38,7 +38,7 @@ stringExtras.loop = '1'; } - const response = await fetchJSON( + const response = await callServerEndpoint( 'upload_multimedia', { multimedia: [multimedia], @@ -64,9 +64,9 @@ 'UPDATE_MULTIMEDIA_MESSAGE_MEDIA'; const deleteUpload = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((id: string) => Promise) => async id => { - await fetchJSON('delete_upload', { id }); + await callServerEndpoint('delete_upload', { id }); }; export { diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js --- a/lib/actions/user-actions.js +++ b/lib/actions/user-actions.js @@ -20,8 +20,8 @@ SubscriptionUpdateResult, } from '../types/subscription-types'; import type { UserInfo, PasswordUpdate } from '../types/user-types'; +import type { CallServerEndpoint } from '../utils/call-server-endpoint'; import { getConfig } from '../utils/config'; -import type { FetchJSON } from '../utils/fetch-json'; import sleep from '../utils/sleep'; const logOutActionTypes = Object.freeze({ @@ -30,14 +30,14 @@ failed: 'LOG_OUT_FAILED', }); const logOut = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( preRequestUserState: PreRequestUserState, ) => Promise) => async preRequestUserState => { let response = null; try { response = await Promise.race([ - fetchJSON('log_out', {}), + callServerEndpoint('log_out', {}), (async () => { await sleep(500); throw new Error('log_out took more than 500ms'); @@ -54,12 +54,12 @@ failed: 'DELETE_ACCOUNT_FAILED', }); const deleteAccount = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( password: string, preRequestUserState: PreRequestUserState, ) => Promise) => async (password, preRequestUserState) => { - const response = await fetchJSON('delete_account', { password }); + const response = await callServerEndpoint('delete_account', { password }); return { currentUserInfo: response.currentUserInfo, preRequestUserState }; }; @@ -68,19 +68,19 @@ success: 'REGISTER_SUCCESS', failed: 'REGISTER_FAILED', }); -const registerFetchJSONOptions = { timeout: 60000 }; +const registerCallServerEndpointOptions = { timeout: 60000 }; const register = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( registerInfo: RegisterInfo, ) => Promise) => async registerInfo => { - const response = await fetchJSON( + const response = await callServerEndpoint( 'create_account', { ...registerInfo, platformDetails: getConfig().platformDetails, }, - registerFetchJSONOptions, + registerCallServerEndpointOptions, ); return { currentUserInfo: response.currentUserInfo, @@ -120,20 +120,20 @@ success: 'LOG_IN_SUCCESS', failed: 'LOG_IN_FAILED', }); -const logInFetchJSONOptions = { timeout: 60000 }; +const logInCallServerEndpointOptions = { timeout: 60000 }; const logIn = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): ((logInInfo: LogInInfo) => Promise) => async logInInfo => { const watchedIDs = threadWatcher.getWatchedIDs(); const { source, ...restLogInInfo } = logInInfo; - const response = await fetchJSON( + const response = await callServerEndpoint( 'log_in', { ...restLogInInfo, watchedIDs, platformDetails: getConfig().platformDetails, }, - logInFetchJSONOptions, + logInCallServerEndpointOptions, ); const userInfos = mergeUserInfos( response.userInfos, @@ -164,11 +164,11 @@ failed: 'CHANGE_USER_PASSWORD_FAILED', }); const changeUserPassword = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( passwordUpdate: PasswordUpdate, ) => Promise) => async passwordUpdate => { - await fetchJSON('update_account', passwordUpdate); + await callServerEndpoint('update_account', passwordUpdate); }; const searchUsersActionTypes = Object.freeze({ @@ -177,11 +177,13 @@ failed: 'SEARCH_USERS_FAILED', }); const searchUsers = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( usernamePrefix: string, ) => Promise) => async usernamePrefix => { - const response = await fetchJSON('search_users', { prefix: usernamePrefix }); + const response = await callServerEndpoint('search_users', { + prefix: usernamePrefix, + }); return { userInfos: response.userInfos, }; @@ -193,11 +195,11 @@ failed: 'UPDATE_SUBSCRIPTION_FAILED', }); const updateSubscription = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( subscriptionUpdate: SubscriptionUpdateRequest, ) => Promise) => async subscriptionUpdate => { - const response = await fetchJSON( + const response = await callServerEndpoint( 'update_user_subscription', subscriptionUpdate, ); @@ -214,19 +216,19 @@ }); const setUserSettings = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( userSettingsRequest: UpdateUserSettingsRequest, ) => Promise) => async userSettingsRequest => { - await fetchJSON('update_user_settings', userSettingsRequest); + await callServerEndpoint('update_user_settings', userSettingsRequest); }; const getSessionPublicKeys = ( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, ): (( data: GetSessionPublicKeysArgs, ) => Promise) => async data => { - return await fetchJSON('get_session_public_keys', data); + return await callServerEndpoint('get_session_public_keys', data); }; export { diff --git a/lib/shared/timeouts.js b/lib/shared/timeouts.js --- a/lib/shared/timeouts.js +++ b/lib/shared/timeouts.js @@ -17,9 +17,10 @@ // unlikely, as the connectivity issue is likely on the client side. export const clientRequestSocketTimeout = 10000; // in milliseconds -// Time after which FetchJSON will timeout a request. When using sockets this is -// preempted by the above timeout, so it really only applies for HTTP requests. -export const fetchJSONTimeout = 10000; // in milliseconds +// Time after which CallServerEndpoint will timeout a request. When using +// sockets this is preempted by the above timeout, so it really only applies +// for HTTP requests. +export const callServerEndpointTimeout = 10000; // in milliseconds // The server expects to get a request at least every three // seconds from the client. If server doesn't get a request diff --git a/lib/types/message-types.js b/lib/types/message-types.js --- a/lib/types/message-types.js +++ b/lib/types/message-types.js @@ -2,7 +2,7 @@ import invariant from 'invariant'; -import type { FetchResultInfoInterface } from '../utils/fetch-json'; +import type { CallServerEndpointResultInfoInterface } from '../utils/call-server-endpoint'; import { type ClientDBMediaInfo } from './media-types'; import type { AddMembersMessageData, @@ -485,14 +485,14 @@ export type SendMessageResult = { +id: string, +time: number, - +interface: FetchResultInfoInterface, + +interface: CallServerEndpointResultInfoInterface, }; export type SendMessagePayload = { +localID: string, +serverID: string, +threadID: string, +time: number, - +interface: FetchResultInfoInterface, + +interface: CallServerEndpointResultInfoInterface, }; export type SendTextMessageRequest = { diff --git a/lib/utils/action-utils.js b/lib/utils/action-utils.js --- a/lib/utils/action-utils.js +++ b/lib/utils/action-utils.js @@ -26,9 +26,12 @@ } from '../types/session-types'; import type { ConnectionStatus } from '../types/socket-types'; import type { CurrentUserInfo } from '../types/user-types'; +import callServerEndpoint from './call-server-endpoint'; +import type { + CallServerEndpoint, + CallServerEndpointOptions, +} from './call-server-endpoint'; import { getConfig } from './config'; -import fetchJSON from './fetch-json'; -import type { FetchJSON, FetchJSONOptions } from './fetch-json'; let nextPromiseIndex = 0; @@ -142,7 +145,9 @@ }; let currentlyWaitingForNewCookie = false; -let fetchJSONCallsWaitingForNewCookie: ((fetchJSON: ?FetchJSON) => void)[] = []; +let callServerEndpointCallsWaitingForNewCookie: (( + callServerEndpoint: ?CallServerEndpoint, +) => void)[] = []; export type DispatchRecoveryAttempt = ( actionTypes: ActionTypes<'LOG_IN_STARTED', 'LOG_IN_SUCCESS', 'LOG_IN_FAILED'>, @@ -180,11 +185,11 @@ return null; } let newSessionChange = null; - let fetchJSONCallback = null; - const boundFetchJSON = async ( + let callServerEndpointCallback = null; + const boundCallServerEndpoint = async ( endpoint: Endpoint, data: { [key: string]: mixed }, - options?: ?FetchJSONOptions, + options?: ?CallServerEndpointOptions, ) => { const innerBoundSetNewSession = ( sessionChange: ClientSessionChange, @@ -194,7 +199,7 @@ setNewSession(dispatch, sessionChange, null, error, source); }; try { - const result = await fetchJSON( + const result = await callServerEndpoint( cookie, innerBoundSetNewSession, () => new Promise(r => r(null)), @@ -207,13 +212,13 @@ data, options, ); - if (fetchJSONCallback) { - fetchJSONCallback(!!newSessionChange); + if (callServerEndpointCallback) { + callServerEndpointCallback(!!newSessionChange); } return result; } catch (e) { - if (fetchJSONCallback) { - fetchJSONCallback(!!newSessionChange); + if (callServerEndpointCallback) { + callServerEndpointCallback(!!newSessionChange); } throw e; } @@ -229,10 +234,10 @@ ) => { const startingPayload = { ...inputStartingPayload, source }; dispatch(wrapActionPromise(actionTypes, promise, null, startingPayload)); - return new Promise(r => (fetchJSONCallback = r)); + return new Promise(r => (callServerEndpointCallback = r)); }; await resolveInvalidatedCookie( - boundFetchJSON, + boundCallServerEndpoint, dispatchRecoveryAttempt, source, ); @@ -241,9 +246,9 @@ // Third param is optional and gets called with newCookie if we get a new cookie // Necessary to propagate cookie in cookieInvalidationRecovery below -function bindCookieAndUtilsIntoFetchJSON( +function bindCookieAndUtilsIntoCallServerEndpoint( params: BindServerCallsParams, -): FetchJSON { +): CallServerEndpoint { const { dispatch, cookie, @@ -264,12 +269,13 @@ error, undefined, ); - // This function gets called before fetchJSON sends a request, to make sure - // that we're not in the middle of trying to recover an invalidated cookie + // This function gets called before callServerEndpoint sends a request, + // to make sure that we're not in the middle of trying to recover + // an invalidated cookie const waitIfCookieInvalidated = () => { if (!getConfig().resolveInvalidatedCookie) { // If there is no resolveInvalidatedCookie function, just let the caller - // fetchJSON instance continue + // callServerEndpoint instance continue return Promise.resolve(null); } if (!currentlyWaitingForNewCookie) { @@ -277,7 +283,7 @@ return Promise.resolve(null); } // Wait to run until we get our new cookie - return new Promise(r => fetchJSONCallsWaitingForNewCookie.push(r)); + return new Promise(r => callServerEndpointCallsWaitingForNewCookie.push(r)); }; // This function is a helper for the next function defined below const attemptToResolveInvalidation = async ( @@ -292,11 +298,11 @@ ); currentlyWaitingForNewCookie = false; - const currentWaitingCalls = fetchJSONCallsWaitingForNewCookie; - fetchJSONCallsWaitingForNewCookie = []; + const currentWaitingCalls = callServerEndpointCallsWaitingForNewCookie; + callServerEndpointCallsWaitingForNewCookie = []; - const newFetchJSON = newSessionChange - ? bindCookieAndUtilsIntoFetchJSON({ + const newCallServerEndpoint = newSessionChange + ? bindCookieAndUtilsIntoCallServerEndpoint({ ...params, cookie: newSessionChange.cookie, sessionID: newSessionChange.sessionID, @@ -304,17 +310,17 @@ }) : null; for (const func of currentWaitingCalls) { - func(newFetchJSON); + func(newCallServerEndpoint); } - return newFetchJSON; + return newCallServerEndpoint; }; - // If this function is called, fetchJSON got a response invalidating its - // cookie, and is wondering if it should just like... give up? Or if there's - // a chance at redemption + // If this function is called, callServerEndpoint got a response invalidating + // its cookie, and is wondering if it should just like... give up? + // Or if there's a chance at redemption const cookieInvalidationRecovery = (sessionChange: ClientSessionChange) => { if (!getConfig().resolveInvalidatedCookie) { // If there is no resolveInvalidatedCookie function, just let the caller - // fetchJSON instance continue + // callServerEndpoint instance continue return Promise.resolve(null); } if (!loggedIn) { @@ -323,14 +329,20 @@ return Promise.resolve(null); } if (currentlyWaitingForNewCookie) { - return new Promise(r => fetchJSONCallsWaitingForNewCookie.push(r)); + return new Promise(r => + callServerEndpointCallsWaitingForNewCookie.push(r), + ); } currentlyWaitingForNewCookie = true; return attemptToResolveInvalidation(sessionChange); }; - return (endpoint: Endpoint, data: Object, options?: ?FetchJSONOptions) => - fetchJSON( + return ( + endpoint: Endpoint, + data: Object, + options?: ?CallServerEndpointOptions, + ) => + callServerEndpoint( cookie, boundSetNewSession, waitIfCookieInvalidated, @@ -345,7 +357,7 @@ ); } -export type ActionFunc = (fetchJSON: FetchJSON) => F; +export type ActionFunc = (callServerEndpoint: CallServerEndpoint) => F; type BindServerCallsParams = { dispatch: Dispatch, cookie: ?string, @@ -357,12 +369,13 @@ // All server calls needs to include some information from the Redux state // (namely, the cookie). This information is used deep in the server call, -// at the point where fetchJSON is called. We don't want to bother propagating -// the cookie (and any future config info that fetchJSON needs) through to the -// server calls so they can pass it to fetchJSON. Instead, we "curry" the cookie -// onto fetchJSON within react-redux's connect's mapStateToProps function, and -// then pass that "bound" fetchJSON that no longer needs the cookie as a -// parameter on to the server call. +// at the point where callServerEndpoint is called. We don't want to bother +// propagating the cookie (and any future config info that callServerEndpoint +// needs) through to the server calls so they can pass it to callServerEndpoint. +// Instead, we "curry" the cookie onto callServerEndpoint within react-redux's +// connect's mapStateToProps function, and then pass that "bound" +// callServerEndpoint that no longer needs the cookie as a parameter on to +// the server call. const baseCreateBoundServerCallsSelector = ( actionFunc: ActionFunc, ): (BindServerCallsParams => F) => @@ -381,7 +394,7 @@ currentUserInfo: ?CurrentUserInfo, connectionStatus: ConnectionStatus, ) => { - const boundFetchJSON = bindCookieAndUtilsIntoFetchJSON({ + const boundCallServerEndpoint = bindCookieAndUtilsIntoCallServerEndpoint({ dispatch, cookie, urlPrefix, @@ -389,7 +402,7 @@ currentUserInfo, connectionStatus, }); - return actionFunc(boundFetchJSON); + return actionFunc(boundCallServerEndpoint); }, ); diff --git a/lib/utils/fetch-json.js b/lib/utils/call-server-endpoint.js rename from lib/utils/fetch-json.js rename to lib/utils/call-server-endpoint.js --- a/lib/utils/fetch-json.js +++ b/lib/utils/call-server-endpoint.js @@ -1,6 +1,6 @@ // @flow -import { fetchJSONTimeout } from '../shared/timeouts'; +import { callServerEndpointTimeout } from '../shared/timeouts'; import { SocketOffline, SocketTimeout } from '../socket/inflight-requests'; import type { Shape } from '../types/core'; import { @@ -20,12 +20,12 @@ import sleep from './sleep'; import { uploadBlob, type UploadBlob } from './upload-blob'; -export type FetchJSONOptions = Shape<{ +export type CallServerEndpointOptions = Shape<{ // null timeout means no timeout, which is the default for uploadBlob +timeout: ?number, // in milliseconds - // getResultInfo will be called right before fetchJSON successfully resolves - // and includes additional information about the request - +getResultInfo: (resultInfo: FetchResultInfo) => mixed, + // getResultInfo will be called right before callServerEndpoint successfully + // resolves and includes additional information about the request + +getResultInfo: (resultInfo: CallServerEndpointResultInfo) => mixed, +blobUpload: boolean | UploadBlob, // the rest (onProgress, abortHandler) only work with blobUpload +onProgress: (percent: number) => void, @@ -33,26 +33,27 @@ +abortHandler: (abort: () => void) => void, }>; -export type FetchResultInfoInterface = 'socket' | 'REST'; -export type FetchResultInfo = { - +interface: FetchResultInfoInterface, +export type CallServerEndpointResultInfoInterface = 'socket' | 'REST'; +export type CallServerEndpointResultInfo = { + +interface: CallServerEndpointResultInfoInterface, }; -export type FetchJSONServerResponse = Shape<{ +export type CallServerEndpointResponse = Shape<{ +cookieChange: ServerSessionChange, +currentUserInfo: CurrentUserInfo, +error: string, +payload: Object, }>; -// You'll notice that this is not the type of the fetchJSON function below. This -// is because the first several parameters to that functon get bound in by the -// helpers in lib/utils/action-utils.js. This type represents the form of the -// fetchJSON function that gets passed to the action function in lib/actions. -export type FetchJSON = ( +// You'll notice that this is not the type of the callServerEndpoint +// function below. This is because the first several parameters to that +// function get bound in by the helpers in lib/utils/action-utils.js. +// This type represents the form of the callServerEndpoint function that +// gets passed to the action function in lib/actions. +export type CallServerEndpoint = ( endpoint: Endpoint, input: Object, - options?: ?FetchJSONOptions, + options?: ?CallServerEndpointOptions, ) => Promise; type RequestData = { @@ -68,20 +69,20 @@ // underlying implementations and prefer for things to be explicit, and XSS // isn't a thing on native. Note that for native, cookie might be null // (indicating we don't have one), and we will then set an empty Cookie header. -async function fetchJSON( +async function callServerEndpoint( cookie: ?string, setNewSession: (sessionChange: ClientSessionChange, error: ?string) => void, - waitIfCookieInvalidated: () => Promise, + waitIfCookieInvalidated: () => Promise, cookieInvalidationRecovery: ( sessionChange: ClientSessionChange, - ) => Promise, + ) => Promise, urlPrefix: string, sessionID: ?string, connectionStatus: ConnectionStatus, socketAPIHandler: ?SocketAPIHandler, endpoint: Endpoint, input: { [key: string]: mixed }, - options?: ?FetchJSONOptions, + options?: ?CallServerEndpointOptions, ): Promise { const possibleReplacement = await waitIfCookieInvalidated(); if (possibleReplacement) { @@ -140,7 +141,7 @@ // is not logged in on web. mergedData.sessionID = sessionID ? sessionID : null; } - const fetchPromise = (async (): Promise => { + const callEndpointPromise = (async (): Promise => { const response = await fetch(url, { method: 'POST', // This is necessary to allow cookie headers to get passed down to us @@ -161,18 +162,18 @@ })(); const timeout = - options && options.timeout ? options.timeout : fetchJSONTimeout; + options && options.timeout ? options.timeout : callServerEndpointTimeout; if (!timeout) { - json = await fetchPromise; + json = await callEndpointPromise; } else { const rejectPromise = (async () => { await sleep(timeout); throw new FetchTimeout( - `fetchJSON timed out call to ${endpoint}`, + `callServerEndpoint timed out call to ${endpoint}`, endpoint, ); })(); - json = await Promise.race([fetchPromise, rejectPromise]); + json = await Promise.race([callEndpointPromise, rejectPromise]); } } @@ -201,4 +202,4 @@ return json; } -export default fetchJSON; +export default callServerEndpoint; diff --git a/lib/utils/config.js b/lib/utils/config.js --- a/lib/utils/config.js +++ b/lib/utils/config.js @@ -5,11 +5,11 @@ import type { LogInActionSource } from '../types/account-types'; import type { PlatformDetails } from '../types/device-types'; import type { DispatchRecoveryAttempt } from './action-utils'; -import type { FetchJSON } from './fetch-json'; +import type { CallServerEndpoint } from './call-server-endpoint'; export type Config = { +resolveInvalidatedCookie: ?( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, dispatchRecoveryAttempt: DispatchRecoveryAttempt, source?: LogInActionSource, ) => Promise, diff --git a/lib/utils/upload-blob.js b/lib/utils/upload-blob.js --- a/lib/utils/upload-blob.js +++ b/lib/utils/upload-blob.js @@ -3,16 +3,19 @@ import invariant from 'invariant'; import _throttle from 'lodash/throttle'; +import type { + CallServerEndpointOptions, + CallServerEndpointResponse, +} from './call-server-endpoint'; import { getConfig } from './config'; -import type { FetchJSONOptions, FetchJSONServerResponse } from './fetch-json'; function uploadBlob( url: string, cookie: ?string, sessionID: ?string, input: { [key: string]: mixed }, - options?: ?FetchJSONOptions, -): Promise { + options?: ?CallServerEndpointOptions, +): Promise { const formData = new FormData(); if (getConfig().setCookieOnRequest) { // We make sure that if setCookieOnRequest is true, we never set cookie to diff --git a/native/account/resolve-invalidated-cookie.js b/native/account/resolve-invalidated-cookie.js --- a/native/account/resolve-invalidated-cookie.js +++ b/native/account/resolve-invalidated-cookie.js @@ -3,7 +3,7 @@ import { logInActionTypes, logIn } from 'lib/actions/user-actions'; import type { LogInActionSource } from 'lib/types/account-types'; import type { DispatchRecoveryAttempt } from 'lib/utils/action-utils'; -import type { FetchJSON } from 'lib/utils/fetch-json'; +import type { CallServerEndpoint } from 'lib/utils/call-server-endpoint'; import { getGlobalNavContext } from '../navigation/icky-global'; import { store } from '../redux/redux-setup'; @@ -11,7 +11,7 @@ import { fetchNativeKeychainCredentials } from './native-credentials'; async function resolveInvalidatedCookie( - fetchJSON: FetchJSON, + callServerEndpoint: CallServerEndpoint, dispatchRecoveryAttempt: DispatchRecoveryAttempt, source?: LogInActionSource, ) { @@ -26,7 +26,7 @@ const { calendarQuery } = extraInfo; await dispatchRecoveryAttempt( logInActionTypes, - logIn(fetchJSON)({ + logIn(callServerEndpoint)({ ...keychainCredentials, ...extraInfo, source, diff --git a/native/input/input-state-container.react.js b/native/input/input-state-container.react.js --- a/native/input/input-state-container.react.js +++ b/native/input/input-state-container.react.js @@ -75,12 +75,12 @@ useServerCall, useDispatchActionPromise, } from 'lib/utils/action-utils'; +import type { + CallServerEndpointOptions, + CallServerEndpointResponse, +} from 'lib/utils/call-server-endpoint'; import { getConfig } from 'lib/utils/config'; import { getMessageForException, cloneError } from 'lib/utils/errors'; -import type { - FetchJSONOptions, - FetchJSONServerResponse, -} from 'lib/utils/fetch-json'; import { values } from 'lib/utils/objects'; import { useIsReportEnabled } from 'lib/utils/report-utils'; @@ -889,8 +889,8 @@ cookie: ?string, sessionID: ?string, input: { [key: string]: mixed }, - options?: ?FetchJSONOptions, - ): Promise => { + options?: ?CallServerEndpointOptions, + ): Promise => { invariant( cookie && input.multimedia &&