diff --git a/lib/utils/action-utils.js b/lib/keyserver-conn/call-keyserver-endpoint-provider.react.js copy from lib/utils/action-utils.js copy to lib/keyserver-conn/call-keyserver-endpoint-provider.react.js --- a/lib/utils/action-utils.js +++ b/lib/keyserver-conn/call-keyserver-endpoint-provider.react.js @@ -1,29 +1,24 @@ // @flow -import invariant from 'invariant'; import _memoize from 'lodash/memoize.js'; -import * as React from 'react'; import { createSelector } from 'reselect'; -import callServerEndpoint from './call-server-endpoint.js'; -import type { - CallServerEndpoint, - CallServerEndpointOptions, -} from './call-server-endpoint.js'; -import { useSelector, useDispatch } from './redux-utils.js'; -import { ashoatKeyserverID } from './validation-utils.js'; -import { setNewSession } from '../keyserver-conn/keyserver-conn-types.js'; +import { setNewSession } from './keyserver-conn-types.js'; import { canResolveKeyserverSessionInvalidation, resolveKeyserverSessionInvalidation, -} from '../keyserver-conn/recovery-utils.js'; -import { serverCallStateSelector } from '../selectors/server-calls.js'; +} from './recovery-utils.js'; import { logInActionSources } from '../types/account-types.js'; import type { PlatformDetails } from '../types/device-types.js'; import type { Endpoint, SocketAPIHandler } from '../types/endpoints.js'; import type { Dispatch } from '../types/redux-types.js'; import type { ClientSessionChange } from '../types/session-types.js'; import type { CurrentUserInfo } from '../types/user-types.js'; +import type { + CallServerEndpoint, + CallServerEndpointOptions, +} from '../utils/call-server-endpoint.js'; +import callServerEndpoint from '../utils/call-server-endpoint.js'; let currentlyWaitingForNewCookie = false; let serverEndpointCallsWaitingForNewCookie: (( @@ -158,7 +153,6 @@ } export type ActionFunc = (callServerEndpoint: CallServerEndpoint) => F; -export type BindServerCall = (serverCall: ActionFunc) => F; export type BindServerCallsParams = { +dispatch: Dispatch, +cookie: ?string, @@ -221,34 +215,6 @@ const createBoundServerCallsSelector: CreateBoundServerCallsSelectorType = (_memoize(baseCreateBoundServerCallsSelector): any); -function useServerCall( - serverCall: ActionFunc, - paramOverride?: ?Partial, -): F { - const dispatch = useDispatch(); - const serverCallState = useSelector( - serverCallStateSelector(ashoatKeyserverID), - ); - return React.useMemo(() => { - const { urlPrefix, isSocketConnected } = serverCallState; - invariant( - !!urlPrefix && - isSocketConnected !== undefined && - isSocketConnected !== null, - 'keyserver missing from keyserverStore', - ); - - return createBoundServerCallsSelector(serverCall)({ - ...serverCallState, - urlPrefix, - isSocketConnected, - dispatch, - ...paramOverride, - keyserverID: ashoatKeyserverID, - }); - }, [serverCall, serverCallState, dispatch, paramOverride]); -} - let socketAPIHandler: ?SocketAPIHandler = null; function registerActiveSocket(passedSocketAPIHandler: ?SocketAPIHandler) { socketAPIHandler = passedSocketAPIHandler; @@ -257,6 +223,5 @@ export { createBoundServerCallsSelector, registerActiveSocket, - useServerCall, bindCookieAndUtilsIntoCallServerEndpoint, }; diff --git a/lib/socket/api-request-handler.react.js b/lib/socket/api-request-handler.react.js --- a/lib/socket/api-request-handler.react.js +++ b/lib/socket/api-request-handler.react.js @@ -4,6 +4,7 @@ import * as React from 'react'; import { InflightRequests } from './inflight-requests.js'; +import { registerActiveSocket } from '../keyserver-conn/call-keyserver-endpoint-provider.react.js'; import { connectionSelector } from '../selectors/keyserver-selectors.js'; import type { APIRequest } from '../types/endpoints.js'; import { @@ -13,7 +14,6 @@ type ConnectionInfo, type APIResponseServerSocketMessage, } from '../types/socket-types.js'; -import { registerActiveSocket } from '../utils/action-utils.js'; import { SocketOffline } from '../utils/errors.js'; import { useSelector } from '../utils/redux-utils.js'; import { ashoatKeyserverID } from '../utils/validation-utils.js'; 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 @@ -1,225 +1,16 @@ // @flow import invariant from 'invariant'; -import _memoize from 'lodash/memoize.js'; import * as React from 'react'; -import { createSelector } from 'reselect'; -import callServerEndpoint from './call-server-endpoint.js'; -import type { - CallServerEndpoint, - CallServerEndpointOptions, -} from './call-server-endpoint.js'; import { useSelector, useDispatch } from './redux-utils.js'; import { ashoatKeyserverID } from './validation-utils.js'; -import { setNewSession } from '../keyserver-conn/keyserver-conn-types.js'; import { - canResolveKeyserverSessionInvalidation, - resolveKeyserverSessionInvalidation, -} from '../keyserver-conn/recovery-utils.js'; + type ActionFunc, + type BindServerCallsParams, + createBoundServerCallsSelector, +} from '../keyserver-conn/call-keyserver-endpoint-provider.react.js'; import { serverCallStateSelector } from '../selectors/server-calls.js'; -import { logInActionSources } from '../types/account-types.js'; -import type { PlatformDetails } from '../types/device-types.js'; -import type { Endpoint, SocketAPIHandler } from '../types/endpoints.js'; -import type { Dispatch } from '../types/redux-types.js'; -import type { ClientSessionChange } from '../types/session-types.js'; -import type { CurrentUserInfo } from '../types/user-types.js'; - -let currentlyWaitingForNewCookie = false; -let serverEndpointCallsWaitingForNewCookie: (( - callServerEndpoint: ?CallServerEndpoint, -) => void)[] = []; - -// Third param is optional and gets called with newCookie if we get a new cookie -// Necessary to propagate cookie in cookieInvalidationRecovery below -function bindCookieAndUtilsIntoCallServerEndpoint( - params: BindServerCallsParams, -): CallServerEndpoint { - const { - dispatch, - cookie, - urlPrefix, - sessionID, - currentUserInfo, - isSocketConnected, - lastCommunicatedPlatformDetails, - keyserverID, - } = params; - const loggedIn = !!(currentUserInfo && !currentUserInfo.anonymous && true); - const boundSetNewSession = ( - sessionChange: ClientSessionChange, - error: ?string, - ) => - setNewSession( - dispatch, - sessionChange, - { - currentUserInfo, - cookiesAndSessions: { [keyserverID]: { cookie, sessionID } }, - }, - error, - undefined, - keyserverID, - ); - const canResolveInvalidation = canResolveKeyserverSessionInvalidation(); - // 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 (!canResolveInvalidation) { - // If there is no way to resolve the session invalidation, - // just let the caller callServerEndpoint instance continue - return Promise.resolve(null); - } - if (!currentlyWaitingForNewCookie) { - // Our cookie seems to be valid - return Promise.resolve(null); - } - // Wait to run until we get our new cookie - return new Promise(r => - serverEndpointCallsWaitingForNewCookie.push(r), - ); - }; - // This function is a helper for the next function defined below - const attemptToResolveInvalidation = async ( - sessionChange: ClientSessionChange, - ) => { - const newAnonymousCookie = sessionChange.cookie; - const newSessionChange = await resolveKeyserverSessionInvalidation( - dispatch, - newAnonymousCookie, - urlPrefix, - logInActionSources.cookieInvalidationResolutionAttempt, - keyserverID, - ); - - currentlyWaitingForNewCookie = false; - const currentWaitingCalls = serverEndpointCallsWaitingForNewCookie; - serverEndpointCallsWaitingForNewCookie = []; - - const newCallServerEndpoint = newSessionChange - ? bindCookieAndUtilsIntoCallServerEndpoint({ - ...params, - cookie: newSessionChange.cookie, - sessionID: newSessionChange.sessionID, - currentUserInfo: newSessionChange.currentUserInfo, - }) - : null; - for (const func of currentWaitingCalls) { - func(newCallServerEndpoint); - } - return newCallServerEndpoint; - }; - // 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 (!canResolveInvalidation) { - // If there is no way to resolve the session invalidation, - // just let the caller callServerEndpoint instance continue - return Promise.resolve(null); - } - if (!loggedIn) { - // We don't want to attempt any use native credentials of a logged out - // user to log-in after a cookieInvalidation while logged out - return Promise.resolve(null); - } - if (currentlyWaitingForNewCookie) { - return new Promise(r => - serverEndpointCallsWaitingForNewCookie.push(r), - ); - } - currentlyWaitingForNewCookie = true; - return attemptToResolveInvalidation(sessionChange); - }; - - return ( - endpoint: Endpoint, - data: Object, - options?: ?CallServerEndpointOptions, - ) => - callServerEndpoint( - cookie, - boundSetNewSession, - waitIfCookieInvalidated, - cookieInvalidationRecovery, - urlPrefix, - sessionID, - isSocketConnected, - lastCommunicatedPlatformDetails, - socketAPIHandler, - endpoint, - data, - dispatch, - options, - loggedIn, - keyserverID, - ); -} - -export type ActionFunc = (callServerEndpoint: CallServerEndpoint) => F; -export type BindServerCall = (serverCall: ActionFunc) => F; -export type BindServerCallsParams = { - +dispatch: Dispatch, - +cookie: ?string, - +urlPrefix: string, - +sessionID: ?string, - +currentUserInfo: ?CurrentUserInfo, - +isSocketConnected: boolean, - +lastCommunicatedPlatformDetails: ?PlatformDetails, - +keyserverID: string, -}; - -// 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 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) => - createSelector( - (state: BindServerCallsParams) => state.dispatch, - (state: BindServerCallsParams) => state.cookie, - (state: BindServerCallsParams) => state.urlPrefix, - (state: BindServerCallsParams) => state.sessionID, - (state: BindServerCallsParams) => state.currentUserInfo, - (state: BindServerCallsParams) => state.isSocketConnected, - (state: BindServerCallsParams) => state.lastCommunicatedPlatformDetails, - (state: BindServerCallsParams) => state.keyserverID, - ( - dispatch: Dispatch, - cookie: ?string, - urlPrefix: string, - sessionID: ?string, - currentUserInfo: ?CurrentUserInfo, - isSocketConnected: boolean, - lastCommunicatedPlatformDetails: ?PlatformDetails, - keyserverID: string, - ) => { - const boundCallServerEndpoint = bindCookieAndUtilsIntoCallServerEndpoint({ - dispatch, - cookie, - urlPrefix, - sessionID, - currentUserInfo, - isSocketConnected, - lastCommunicatedPlatformDetails, - keyserverID, - }); - return actionFunc(boundCallServerEndpoint); - }, - ); - -type CreateBoundServerCallsSelectorType = ( - ActionFunc, -) => BindServerCallsParams => F; -const createBoundServerCallsSelector: CreateBoundServerCallsSelectorType = - (_memoize(baseCreateBoundServerCallsSelector): any); function useServerCall( serverCall: ActionFunc, @@ -249,14 +40,4 @@ }, [serverCall, serverCallState, dispatch, paramOverride]); } -let socketAPIHandler: ?SocketAPIHandler = null; -function registerActiveSocket(passedSocketAPIHandler: ?SocketAPIHandler) { - socketAPIHandler = passedSocketAPIHandler; -} - -export { - createBoundServerCallsSelector, - registerActiveSocket, - useServerCall, - bindCookieAndUtilsIntoCallServerEndpoint, -}; +export { useServerCall }; diff --git a/lib/utils/keyserver-call.js b/lib/utils/keyserver-call.js --- a/lib/utils/keyserver-call.js +++ b/lib/utils/keyserver-call.js @@ -4,8 +4,6 @@ import * as React from 'react'; import { createSelector } from 'reselect'; -import { bindCookieAndUtilsIntoCallServerEndpoint } from './action-utils.js'; -import type { BindServerCallsParams } from './action-utils.js'; import type { CallServerEndpoint, CallServerEndpointOptions, @@ -13,6 +11,10 @@ import { promiseAll } from './promises.js'; import { useSelector, useDispatch } from './redux-utils.js'; import { useDerivedObject } from '../hooks/objects.js'; +import { + bindCookieAndUtilsIntoCallServerEndpoint, + type BindServerCallsParams, +} from '../keyserver-conn/call-keyserver-endpoint-provider.react.js'; import type { PlatformDetails } from '../types/device-types.js'; import type { Endpoint } from '../types/endpoints.js'; import type { KeyserverInfo } from '../types/keyserver-types.js'; diff --git a/native/account/siwe-panel.react.js b/native/account/siwe-panel.react.js --- a/native/account/siwe-panel.react.js +++ b/native/account/siwe-panel.react.js @@ -10,12 +10,10 @@ getSIWENonceActionTypes, siweAuthActionTypes, } from 'lib/actions/siwe-actions.js'; +import type { BindServerCallsParams } from 'lib/keyserver-conn/call-keyserver-endpoint-provider.react.js'; import { createLoadingStatusSelector } from 'lib/selectors/loading-selectors.js'; import type { SIWEWebViewMessage, SIWEResult } from 'lib/types/siwe-types.js'; -import { - useServerCall, - type BindServerCallsParams, -} from 'lib/utils/action-utils.js'; +import { useServerCall } from 'lib/utils/action-utils.js'; import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js'; import { useKeyboardHeight } from '../keyboard/keyboard-hooks.js';