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 @@ -10,6 +10,7 @@ UpdateUserSettingsRequest, PolicyAcknowledgmentRequest, ClaimUsernameResponse, + LogInResponse, } from '../types/account-types.js'; import type { UpdateUserAvatarRequest, @@ -31,12 +32,17 @@ SubscriptionUpdateRequest, SubscriptionUpdateResult, } from '../types/subscription-types.js'; +import type { RawThreadInfo } from '../types/thread-types'; import type { UserInfo, PasswordUpdate, LoggedOutUserInfo, } from '../types/user-types.js'; -import { extractKeyserverIDFromID } from '../utils/action-utils.js'; +import { + extractKeyserverIDFromID, + sortThreadIDsPerKeyserver, + sortCalendarQueryPerKeyserver, +} from '../utils/action-utils.js'; import type { CallServerEndpoint, CallServerEndpointOptions, @@ -198,50 +204,103 @@ const logInCallServerEndpointOptions = { timeout: 60000 }; const logIn = ( - callServerEndpoint: CallServerEndpoint, - ): ((logInInfo: LogInInfo) => Promise) => + callKeyserverEndpoint: CallKeyserverEndpoint, + ): ((input: LogInInfo) => Promise) => async logInInfo => { const watchedIDs = threadWatcher.getWatchedIDs(); - const { logInActionSource, ...restLogInInfo } = logInInfo; + const { logInActionSource, calendarQuery, ...restLogInInfo } = logInInfo; - const deviceTokenUpdateRequest = - logInInfo.deviceTokenUpdateRequest[ashoatKeyserverID]; + // Eventually the list of keyservers will be fetched from the + // identity service + const keyserverIDs = [ashoatKeyserverID]; - const response = await callServerEndpoint( - 'log_in', - { + const watchedIDsPerKeyserver = sortThreadIDsPerKeyserver(watchedIDs); + const calendarQueryPerKeyserver = sortCalendarQueryPerKeyserver( + calendarQuery, + keyserverIDs, + ); + + const requests = {}; + for (const keyserverID of keyserverIDs) { + requests[keyserverID] = { ...restLogInInfo, - deviceTokenUpdateRequest, + deviceTokenUpdateRequest: + logInInfo.deviceTokenUpdateRequest[keyserverID], source: logInActionSource, - watchedIDs, + watchedIDs: watchedIDsPerKeyserver[keyserverID] ?? [], + calendarQuery: calendarQueryPerKeyserver[keyserverID], platformDetails: getConfig().platformDetails, - }, + }; + } + + const responses: { +[string]: LogInResponse } = await callKeyserverEndpoint( + 'log_in', + requests, logInCallServerEndpointOptions, ); - const userInfos = mergeUserInfos( - response.userInfos, - response.cookieChange.userInfos, - ); + + const userInfosArrays = []; + + let threadInfos: { +[id: string]: RawThreadInfo } = {}; + const calendarResult = { + calendarQuery: logInInfo.calendarQuery, + rawEntryInfos: [], + }; + const messagesResult = { + messageInfos: [], + truncationStatus: {}, + watchedIDsAtRequestTime: watchedIDs, + currentAsOf: {}, + }; + let updatesCurrentAsOf: { +[string]: number } = {}; + for (const keyserverID in responses) { + threadInfos = { + ...responses[keyserverID].cookieChange.threadInfos, + ...threadInfos, + }; + if (responses[keyserverID].rawEntryInfos) { + calendarResult.rawEntryInfos = calendarResult.rawEntryInfos.concat( + responses[keyserverID].rawEntryInfos, + ); + } + messagesResult.messageInfos = messagesResult.messageInfos.concat( + responses[keyserverID].rawMessageInfos, + ); + messagesResult.truncationStatus = { + ...messagesResult.truncationStatus, + ...responses[keyserverID].truncationStatuses, + }; + messagesResult.currentAsOf = { + ...messagesResult.currentAsOf, + [keyserverID]: responses[keyserverID].serverTime, + }; + updatesCurrentAsOf = { + ...updatesCurrentAsOf, + [keyserverID]: responses[keyserverID].serverTime, + }; + userInfosArrays.push(responses[keyserverID].userInfos); + userInfosArrays.push(responses[keyserverID].cookieChange.userInfos); + } + + const userInfos = mergeUserInfos(...userInfosArrays); + return { - threadInfos: response.cookieChange.threadInfos, - currentUserInfo: response.currentUserInfo, - calendarResult: { - calendarQuery: logInInfo.calendarQuery, - rawEntryInfos: response.rawEntryInfos, - }, - messagesResult: { - messageInfos: response.rawMessageInfos, - truncationStatus: response.truncationStatuses, - watchedIDsAtRequestTime: watchedIDs, - currentAsOf: response.serverTime, - }, + threadInfos, + currentUserInfo: responses[ashoatKeyserverID].currentUserInfo, + calendarResult, + messagesResult, userInfos, - updatesCurrentAsOf: response.serverTime, + updatesCurrentAsOf, logInActionSource: logInInfo.logInActionSource, - notAcknowledgedPolicies: response.notAcknowledgedPolicies, + notAcknowledgedPolicies: + responses[ashoatKeyserverID].notAcknowledgedPolicies, }; }; +function useLogIn(): (input: LogInInfo) => Promise { + return useKeyserverCall(logIn); +} + const changeUserPasswordActionTypes = Object.freeze({ started: 'CHANGE_USER_PASSWORD_STARTED', success: 'CHANGE_USER_PASSWORD_SUCCESS', @@ -421,7 +480,8 @@ getOlmSessionInitializationDataActionTypes, getOlmSessionInitializationData, mergeUserInfos, - logIn, + logIn as logInRawAction, + useLogIn, logInActionTypes, useLogOut, logOutActionTypes, diff --git a/lib/reducers/message-reducer.js b/lib/reducers/message-reducer.js --- a/lib/reducers/message-reducer.js +++ b/lib/reducers/message-reducer.js @@ -753,7 +753,7 @@ freshMessageStore( messagesResult.messageInfos, messagesResult.truncationStatus, - messagesResult.currentAsOf, + messagesResult.currentAsOf[ashoatKeyserverID], newThreadInfos, ); diff --git a/lib/reducers/updates-reducer.js b/lib/reducers/updates-reducer.js --- a/lib/reducers/updates-reducer.js +++ b/lib/reducers/updates-reducer.js @@ -8,6 +8,7 @@ incrementalStateSyncActionType, } from '../types/socket-types.js'; import { processUpdatesActionType } from '../types/update-types.js'; +import { ashoatKeyserverID } from '../utils/validation-utils.js'; function reduceUpdatesCurrentAsOf( currentAsOf: number, @@ -17,7 +18,7 @@ action.type === logInActionTypes.success || action.type === siweAuthActionTypes.success ) { - return action.payload.updatesCurrentAsOf; + return action.payload.updatesCurrentAsOf[ashoatKeyserverID]; } else if (action.type === fullStateSyncActionType) { return action.payload.updatesCurrentAsOf; } else if (action.type === incrementalStateSyncActionType) { diff --git a/lib/types/account-types.js b/lib/types/account-types.js --- a/lib/types/account-types.js +++ b/lib/types/account-types.js @@ -155,7 +155,7 @@ +messagesResult: GenericMessagesResult, +userInfos: $ReadOnlyArray, +calendarResult: CalendarResult, - +updatesCurrentAsOf: number, + +updatesCurrentAsOf: { +[keyserverID: string]: number }, +logInActionSource: LogInActionSource, +notAcknowledgedPolicies?: $ReadOnlyArray, }; 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 @@ -644,7 +644,7 @@ +messageInfos: RawMessageInfo[], +truncationStatus: MessageTruncationStatuses, +watchedIDsAtRequestTime: $ReadOnlyArray, - +currentAsOf: number, + +currentAsOf: { +[keyserverID: string]: number }, }; export type SaveMessagesPayload = { diff --git a/native/account/log-in-panel.react.js b/native/account/log-in-panel.react.js --- a/native/account/log-in-panel.react.js +++ b/native/account/log-in-panel.react.js @@ -7,7 +7,7 @@ import { logInActionTypes, - logIn, + useLogIn, getOlmSessionInitializationDataActionTypes, } from 'lib/actions/user-actions.js'; import { @@ -27,7 +27,6 @@ } from 'lib/types/account-types.js'; import type { LoadingStatus } from 'lib/types/loading-types.js'; import { - useServerCall, useDispatchActionPromise, type DispatchActionPromise, } from 'lib/utils/action-utils.js'; @@ -386,7 +385,7 @@ ); const dispatchActionPromise = useDispatchActionPromise(); - const callLogIn = useServerCall(logIn); + const callLogIn = useLogIn(); const getInitialNotificationsEncryptedMessage = useInitialNotificationsEncryptedMessage(); 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 @@ -1,6 +1,6 @@ // @flow -import { logInActionTypes, logIn } from 'lib/actions/user-actions.js'; +import { logInActionTypes, logInRawAction } from 'lib/actions/user-actions.js'; import type { LogInActionSource } from 'lib/types/account-types.js'; import type { DispatchRecoveryAttempt } from 'lib/utils/action-utils.js'; import type { CallServerEndpoint } from 'lib/utils/call-server-endpoint.js'; @@ -37,7 +37,7 @@ const { calendarQuery } = extraInfo; await dispatchRecoveryAttempt( logInActionTypes, - logIn(callServerEndpoint)({ + logInRawAction(callServerEndpoint)({ ...keychainCredentials, ...extraInfo, logInActionSource, diff --git a/web/account/traditional-login-form.react.js b/web/account/traditional-login-form.react.js --- a/web/account/traditional-login-form.react.js +++ b/web/account/traditional-login-form.react.js @@ -3,7 +3,7 @@ import invariant from 'invariant'; import * as React from 'react'; -import { logIn, logInActionTypes } from 'lib/actions/user-actions.js'; +import { useLogIn, logInActionTypes } from 'lib/actions/user-actions.js'; import { useModalContext } from 'lib/components/modal-provider.react.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import { @@ -16,10 +16,7 @@ } from 'lib/types/account-types.js'; import { logInActionSources } from 'lib/types/account-types.js'; import type { SignedIdentityKeysBlob } from 'lib/types/crypto-types.js'; -import { - useDispatchActionPromise, - useServerCall, -} from 'lib/utils/action-utils.js'; +import { useDispatchActionPromise } from 'lib/utils/action-utils.js'; import { useSignedIdentityKeysBlob } from './account-hooks.js'; import HeaderSeparator from './header-separator.react.js'; @@ -35,7 +32,7 @@ function TraditionalLoginForm(): React.Node { const inputDisabled = useSelector(loadingStatusSelector) === 'loading'; const loginExtraInfo = useSelector(webLogInExtraInfoSelector); - const callLogIn = useServerCall(logIn); + const callLogIn = useLogIn(); const dispatchActionPromise = useDispatchActionPromise(); const modalContext = useModalContext();