diff --git a/lib/selectors/keyserver-selectors.js b/lib/selectors/keyserver-selectors.js --- a/lib/selectors/keyserver-selectors.js +++ b/lib/selectors/keyserver-selectors.js @@ -34,10 +34,15 @@ const currentAsOfSelector: (state: AppState) => number = (state: AppState) => state.messageStore.currentAsOf[ashoatKeyserverID] ?? 0; +const urlPrefixSelector: (state: AppState) => ?string = (state: AppState) => + state.keyserverStore.keyserverInfos[ashoatKeyserverID]?.urlPrefix ?? + state.urlPrefix; + export { cookieSelector, cookiesSelector, sessionIDSelector, updatesCurrentAsOfSelector, currentAsOfSelector, + urlPrefixSelector, }; diff --git a/lib/selectors/server-calls.js b/lib/selectors/server-calls.js --- a/lib/selectors/server-calls.js +++ b/lib/selectors/server-calls.js @@ -2,7 +2,11 @@ import { createSelector } from 'reselect'; -import { cookieSelector, sessionIDSelector } from './keyserver-selectors.js'; +import { + cookieSelector, + sessionIDSelector, + urlPrefixSelector, +} from './keyserver-selectors.js'; import type { LastCommunicatedPlatformDetails } from '../types/device-types.js'; import type { AppState } from '../types/redux-types.js'; import { type ConnectionStatus } from '../types/socket-types.js'; @@ -10,7 +14,7 @@ export type ServerCallState = { +cookie: ?string, - +urlPrefix: string, + +urlPrefix: ?string, +sessionID: ?string, +currentUserInfo: ?CurrentUserInfo, +connectionStatus: ConnectionStatus, @@ -20,14 +24,14 @@ const serverCallStateSelector: (state: AppState) => ServerCallState = createSelector( cookieSelector, - (state: AppState) => state.urlPrefix, + urlPrefixSelector, sessionIDSelector, (state: AppState) => state.currentUserInfo, (state: AppState) => state.connection.status, (state: AppState) => state.lastCommunicatedPlatformDetails, ( cookie: ?string, - urlPrefix: string, + urlPrefix: ?string, sessionID: ?string, currentUserInfo: ?CurrentUserInfo, connectionStatus: ConnectionStatus, 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,5 +1,6 @@ // @flow +import invariant from 'invariant'; import _memoize from 'lodash/memoize.js'; import * as React from 'react'; import { useSelector, useDispatch } from 'react-redux'; @@ -429,15 +430,17 @@ ): F { const dispatch = useDispatch(); const serverCallState = useSelector(serverCallStateSelector); - return React.useMemo( - () => - createBoundServerCallsSelector(serverCall)({ - ...serverCallState, - dispatch, - ...paramOverride, - }), - [serverCall, dispatch, serverCallState, paramOverride], - ); + return React.useMemo(() => { + const { urlPrefix } = serverCallState; + invariant(urlPrefix, 'missing urlPrefix for given keyserver id'); + + return createBoundServerCallsSelector(serverCall)({ + ...serverCallState, + urlPrefix, + dispatch, + ...paramOverride, + }); + }, [serverCall, serverCallState, dispatch, paramOverride]); } let socketAPIHandler: ?SocketAPIHandler = null; diff --git a/native/account/logged-out-modal.react.js b/native/account/logged-out-modal.react.js --- a/native/account/logged-out-modal.react.js +++ b/native/account/logged-out-modal.react.js @@ -1,6 +1,7 @@ // @flow import Icon from '@expo/vector-icons/FontAwesome.js'; +import invariant from 'invariant'; import _isEqual from 'lodash/fp/isEqual.js'; import * as React from 'react'; import { @@ -18,7 +19,10 @@ import { useDispatch } from 'react-redux'; import { resetUserStateActionType } from 'lib/actions/user-actions.js'; -import { cookieSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + cookieSelector, + urlPrefixSelector, +} from 'lib/selectors/keyserver-selectors.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { logInActionSources } from 'lib/types/account-types.js'; import type { Dispatch } from 'lib/types/redux-types.js'; @@ -776,7 +780,8 @@ ); const persistedStateLoaded = usePersistedStateLoaded(); const cookie = useSelector(cookieSelector); - const urlPrefix = useSelector(state => state.urlPrefix); + const urlPrefix = useSelector(urlPrefixSelector); + invariant(urlPrefix, "missing urlPrefix for ashoat's keyserver"); const loggedIn = useSelector(isLoggedIn); const dimensions = useSelector(derivedDimensionsInfoSelector); const splashStyle = useSelector(splashStyleSelector); diff --git a/native/data/sqlite-data-handler.js b/native/data/sqlite-data-handler.js --- a/native/data/sqlite-data-handler.js +++ b/native/data/sqlite-data-handler.js @@ -1,5 +1,6 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { useDispatch } from 'react-redux'; @@ -7,7 +8,10 @@ import { MediaCacheContext } from 'lib/components/media-cache-provider.react.js'; import { reportStoreOpsHandlers } from 'lib/ops/report-store-ops.js'; import { threadStoreOpsHandlers } from 'lib/ops/thread-store-ops.js'; -import { cookieSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + cookieSelector, + urlPrefixSelector, +} from 'lib/selectors/keyserver-selectors.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { logInActionSources, @@ -34,7 +38,8 @@ state => !!(state._persist && state._persist.rehydrated), ); const cookie = useSelector(cookieSelector); - const urlPrefix = useSelector(state => state.urlPrefix); + const urlPrefix = useSelector(urlPrefixSelector); + invariant(urlPrefix, "missing urlPrefix for ashoat's keyserver"); const staffCanSee = useStaffCanSee(); const { staffUserHasBeenLoggedIn } = React.useContext(StaffContext); const loggedIn = useSelector(isLoggedIn); diff --git a/native/profile/custom-server-modal.react.js b/native/profile/custom-server-modal.react.js --- a/native/profile/custom-server-modal.react.js +++ b/native/profile/custom-server-modal.react.js @@ -1,9 +1,11 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { Text } from 'react-native'; import { useDispatch } from 'react-redux'; +import { urlPrefixSelector } from 'lib/selectors/keyserver-selectors.js'; import type { Dispatch } from 'lib/types/redux-types.js'; import { setURLPrefix } from 'lib/utils/url-utils.js'; @@ -117,7 +119,8 @@ const ConnectedCustomServerModal: React.ComponentType = React.memo(function ConnectedCustomServerModal(props: BaseProps) { - const urlPrefix = useSelector(state => state.urlPrefix); + const urlPrefix = useSelector(urlPrefixSelector); + invariant(urlPrefix, "missing urlPrefix for ashoat's keyserver"); const customServer = useSelector(state => state.customServer); const styles = useStyles(unboundStyles); const dispatch = useDispatch(); diff --git a/native/profile/dev-tools.react.js b/native/profile/dev-tools.react.js --- a/native/profile/dev-tools.react.js +++ b/native/profile/dev-tools.react.js @@ -1,10 +1,12 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { View, Text, Platform } from 'react-native'; import { ScrollView } from 'react-native-gesture-handler'; import { useDispatch } from 'react-redux'; +import { urlPrefixSelector } from 'lib/selectors/keyserver-selectors.js'; import type { Dispatch } from 'lib/types/redux-types.js'; import { setURLPrefix } from 'lib/utils/url-utils.js'; @@ -234,7 +236,8 @@ const ConnectedDevTools: React.ComponentType = React.memo( function ConnectedDevTools(props: BaseProps) { - const urlPrefix = useSelector(state => state.urlPrefix); + const urlPrefix = useSelector(urlPrefixSelector); + invariant(urlPrefix, "missing urlPrefix for ashoat's keyserver"); const customServer = useSelector(state => state.customServer); const colors = useColors(); const styles = useStyles(unboundStyles); diff --git a/native/selectors/socket-selectors.js b/native/selectors/socket-selectors.js --- a/native/selectors/socket-selectors.js +++ b/native/selectors/socket-selectors.js @@ -2,7 +2,10 @@ import { createSelector } from 'reselect'; -import { cookieSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + cookieSelector, + urlPrefixSelector, +} from 'lib/selectors/keyserver-selectors.js'; import { getClientResponsesSelector, sessionStateFuncSelector, @@ -24,16 +27,22 @@ import type { AppState } from '../redux/state-types.js'; import type { NavPlusRedux } from '../types/selector-types.js'; -const openSocketSelector: (state: AppState) => () => WebSocket = createSelector( - (state: AppState) => state.urlPrefix, - // We don't actually use the cookie in the socket open function, but we do use - // it in the initial message, and when the cookie changes the socket needs to - // be reopened. By including the cookie here, whenever the cookie changes this - // function will change, which tells the Socket component to restart the - // connection. - cookieSelector, - createOpenSocketFunction, -); +const openSocketSelector: (state: AppState) => ?() => WebSocket = + createSelector( + urlPrefixSelector, + // We don't actually use the cookie in the socket open function, + // but we do use it in the initial message, and when the cookie changes + // the socket needs to be reopened. By including the cookie here, + // whenever the cookie changes this function will change, + // which tells the Socket component to restart the connection. + cookieSelector, + (urlPrefix: ?string) => { + if (!urlPrefix) { + return null; + } + return createOpenSocketFunction(urlPrefix); + }, + ); const sessionIdentificationSelector: ( state: AppState, diff --git a/native/socket.react.js b/native/socket.react.js --- a/native/socket.react.js +++ b/native/socket.react.js @@ -1,11 +1,15 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { useDispatch } from 'react-redux'; import { logOut, logOutActionTypes } from 'lib/actions/user-actions.js'; import { preRequestUserStateSelector } from 'lib/selectors/account-selectors.js'; -import { cookieSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + cookieSelector, + urlPrefixSelector, +} from 'lib/selectors/keyserver-selectors.js'; import { isLoggedIn } from 'lib/selectors/user-selectors.js'; import { accountHasPassword } from 'lib/shared/account-utils.js'; import Socket, { type BaseSocketProps } from 'lib/socket/socket.react.js'; @@ -39,7 +43,8 @@ const navContext = React.useContext(NavContext); const cookie = useSelector(cookieSelector); - const urlPrefix = useSelector(state => state.urlPrefix); + const urlPrefix = useSelector(urlPrefixSelector); + invariant(urlPrefix, 'missing urlPrefix for given keyserver id'); const connection = useSelector(state => state.connection); const frozen = useSelector(state => state.frozen); const active = useSelector( @@ -51,6 +56,7 @@ const currentUserInfo = useSelector(state => state.currentUserInfo); const openSocket = useSelector(openSocketSelector); + invariant(openSocket, 'openSocket failed to be created'); const sessionIdentification = useSelector(sessionIdentificationSelector); const preRequestUserState = useSelector(preRequestUserStateSelector); diff --git a/web/selectors/socket-selectors.js b/web/selectors/socket-selectors.js --- a/web/selectors/socket-selectors.js +++ b/web/selectors/socket-selectors.js @@ -3,7 +3,10 @@ import olm from '@commapp/olm'; import { createSelector } from 'reselect'; -import { sessionIDSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + sessionIDSelector, + urlPrefixSelector, +} from 'lib/selectors/keyserver-selectors.js'; import { getClientResponsesSelector, sessionStateFuncSelector, @@ -28,10 +31,13 @@ import { initOlm } from '../olm/olm-utils.js'; import type { AppState } from '../redux/redux-setup.js'; -const openSocketSelector: (state: AppState) => () => WebSocket = createSelector( - (state: AppState) => state.urlPrefix, - createOpenSocketFunction, -); +const openSocketSelector: (state: AppState) => ?() => WebSocket = + createSelector(urlPrefixSelector, (urlPrefix: ?string) => { + if (!urlPrefix) { + return null; + } + return createOpenSocketFunction(urlPrefix); + }); const sessionIdentificationSelector: ( state: AppState, diff --git a/web/socket.react.js b/web/socket.react.js --- a/web/socket.react.js +++ b/web/socket.react.js @@ -1,11 +1,15 @@ // @flow +import invariant from 'invariant'; import * as React from 'react'; import { useDispatch } from 'react-redux'; import { logOut } from 'lib/actions/user-actions.js'; import { preRequestUserStateSelector } from 'lib/selectors/account-selectors.js'; -import { cookieSelector } from 'lib/selectors/keyserver-selectors.js'; +import { + cookieSelector, + urlPrefixSelector, +} from 'lib/selectors/keyserver-selectors.js'; import Socket, { type BaseSocketProps } from 'lib/socket/socket.react.js'; import { useServerCall, @@ -27,7 +31,8 @@ const WebSocket: React.ComponentType = React.memo(function WebSocket(props) { const cookie = useSelector(cookieSelector); - const urlPrefix = useSelector(state => state.urlPrefix); + const urlPrefix = useSelector(urlPrefixSelector); + invariant(urlPrefix, 'missing urlPrefix for given keyserver id'); const connection = useSelector(state => state.connection); const active = useSelector( state => @@ -37,6 +42,7 @@ ); const openSocket = useSelector(openSocketSelector); + invariant(openSocket, 'openSocket failed to be created'); const sessionIdentification = useSelector(sessionIdentificationSelector); const preRequestUserState = useSelector(preRequestUserStateSelector); const getClientResponses = useSelector(webGetClientResponsesSelector);