diff --git a/keyserver/src/shared/state-sync/current-user-state-sync-spec.js b/keyserver/src/shared/state-sync/current-user-state-sync-spec.js --- a/keyserver/src/shared/state-sync/current-user-state-sync-spec.js +++ b/keyserver/src/shared/state-sync/current-user-state-sync-spec.js @@ -11,6 +11,7 @@ CurrentUserInfo, CurrentUserInfo, CurrentUserInfo, + void, > = Object.freeze({ fetch(viewer: Viewer) { return fetchCurrentUserInfo(viewer); diff --git a/keyserver/src/shared/state-sync/entries-state-sync-spec.js b/keyserver/src/shared/state-sync/entries-state-sync-spec.js --- a/keyserver/src/shared/state-sync/entries-state-sync-spec.js +++ b/keyserver/src/shared/state-sync/entries-state-sync-spec.js @@ -7,6 +7,7 @@ RawEntryInfo, RawEntryInfos, } from 'lib/types/entry-types.js'; +import type { ClientEntryInconsistencyReportCreationRequest } from 'lib/types/report-types.js'; import type { ServerStateSyncSpec } from './state-sync-spec.js'; import { @@ -19,6 +20,7 @@ RawEntryInfos, $ReadOnlyArray, RawEntryInfo, + Array, > = Object.freeze({ async fetch(viewer: Viewer, ids?: $ReadOnlySet) { if (ids) { diff --git a/keyserver/src/shared/state-sync/state-sync-spec.js b/keyserver/src/shared/state-sync/state-sync-spec.js --- a/keyserver/src/shared/state-sync/state-sync-spec.js +++ b/keyserver/src/shared/state-sync/state-sync-spec.js @@ -5,11 +5,16 @@ import type { Viewer } from '../../session/viewer.js'; -export type ServerStateSyncSpec = { +export type ServerStateSyncSpec< + Infos, + FullSocketSyncPayload, + Info, + Inconsistencies, +> = { +fetch: (viewer: Viewer, ids?: $ReadOnlySet) => Promise, +fetchFullSocketSyncPayload: ( viewer: Viewer, calendarQuery: $ReadOnlyArray, ) => Promise, - ...StateSyncSpec, + ...StateSyncSpec, }; diff --git a/keyserver/src/shared/state-sync/state-sync-specs.js b/keyserver/src/shared/state-sync/state-sync-specs.js --- a/keyserver/src/shared/state-sync/state-sync-specs.js +++ b/keyserver/src/shared/state-sync/state-sync-specs.js @@ -14,5 +14,5 @@ }); (serverStateSyncSpecs: { - +[string]: ServerStateSyncSpec, + +[string]: ServerStateSyncSpec, }); diff --git a/keyserver/src/shared/state-sync/threads-state-sync-spec.js b/keyserver/src/shared/state-sync/threads-state-sync-spec.js --- a/keyserver/src/shared/state-sync/threads-state-sync-spec.js +++ b/keyserver/src/shared/state-sync/threads-state-sync-spec.js @@ -1,6 +1,7 @@ // @flow import { threadsStateSyncSpec as libSpec } from 'lib/shared/state-sync/threads-state-sync-spec.js'; +import type { ClientThreadInconsistencyReportCreationRequest } from 'lib/types/report-types.js'; import { type RawThreadInfos, type RawThreadInfo, @@ -14,6 +15,7 @@ RawThreadInfos, RawThreadInfos, RawThreadInfo, + Array, > = Object.freeze({ async fetch(viewer: Viewer, ids?: $ReadOnlySet) { const filter = ids ? { threadIDs: ids } : undefined; diff --git a/keyserver/src/shared/state-sync/users-state-sync-spec.js b/keyserver/src/shared/state-sync/users-state-sync-spec.js --- a/keyserver/src/shared/state-sync/users-state-sync-spec.js +++ b/keyserver/src/shared/state-sync/users-state-sync-spec.js @@ -1,6 +1,7 @@ // @flow import { usersStateSyncSpec as libSpec } from 'lib/shared/state-sync/users-state-sync-spec.js'; +import type { UserInconsistencyReportCreationRequest } from 'lib/types/report-types.js'; import type { UserInfos, UserInfo } from 'lib/types/user-types.js'; import { values } from 'lib/utils/objects.js'; @@ -12,6 +13,7 @@ UserInfos, $ReadOnlyArray, UserInfo, + Array, > = Object.freeze({ fetch(viewer: Viewer, ids?: $ReadOnlySet) { if (ids) { diff --git a/lib/reducers/entry-reducer.js b/lib/reducers/entry-reducer.js --- a/lib/reducers/entry-reducer.js +++ b/lib/reducers/entry-reducer.js @@ -39,23 +39,13 @@ deleteAccountActionTypes, logInActionTypes, } from '../actions/user-actions.js'; -import { - entryID, - filterRawEntryInfosByCalendarQuery, - serverEntryInfosObject, -} from '../shared/entry-utils.js'; +import { entryID } from '../shared/entry-utils.js'; +import { stateSyncSpecs } from '../shared/state-sync/state-sync-specs.js'; import { threadInFilterList } from '../shared/thread-utils.js'; import { updateSpecs } from '../shared/updates/update-specs.js'; -import type { - RawEntryInfo, - EntryStore, - CalendarQuery, -} from '../types/entry-types.js'; +import type { RawEntryInfo, EntryStore } from '../types/entry-types.js'; import type { BaseAction } from '../types/redux-types.js'; -import { - type ClientEntryInconsistencyReportCreationRequest, - reportTypes, -} from '../types/report-types.js'; +import { type ClientEntryInconsistencyReportCreationRequest } from '../types/report-types.js'; import { serverRequestTypes, processServerRequestsActionType, @@ -69,13 +59,9 @@ type ClientUpdateInfo, processUpdatesActionType, } from '../types/update-types.js'; -import { actionLogger } from '../utils/action-logger.js'; import { setNewSessionActionType } from '../utils/action-utils.js'; -import { getConfig } from '../utils/config.js'; import { dateString } from '../utils/date-utils.js'; import { values } from '../utils/objects.js'; -import { generateReportID } from '../utils/report-utils.js'; -import { sanitizeActionSecrets } from '../utils/sanitization.js'; function daysToEntriesFromEntryInfos( entryInfos: $ReadOnlyArray, @@ -623,11 +609,10 @@ ); } - const newInconsistencies = findInconsistencies( + const newInconsistencies = stateSyncSpecs.entries.findStoreInconsistencies( action, entryInfos, updatedEntryInfos, - action.payload.calendarQuery, ); return [ @@ -660,41 +645,6 @@ return mergedEntryInfos; } -const emptyArray = []; -function findInconsistencies( - action: BaseAction, - beforeStateCheck: { +[id: string]: RawEntryInfo }, - afterStateCheck: { +[id: string]: RawEntryInfo }, - calendarQuery: CalendarQuery, -): ClientEntryInconsistencyReportCreationRequest[] { - // We don't want to bother reporting an inconsistency if it's just because of - // extraneous EntryInfos (not within the current calendarQuery) on either side - const filteredBeforeResult = filterRawEntryInfosByCalendarQuery( - serverEntryInfosObject(values(beforeStateCheck)), - calendarQuery, - ); - const filteredAfterResult = filterRawEntryInfosByCalendarQuery( - serverEntryInfosObject(values(afterStateCheck)), - calendarQuery, - ); - if (_isEqual(filteredBeforeResult)(filteredAfterResult)) { - return emptyArray; - } - return [ - { - type: reportTypes.ENTRY_INCONSISTENCY, - platformDetails: getConfig().platformDetails, - beforeAction: beforeStateCheck, - action: sanitizeActionSecrets(action), - calendarQuery, - pushResult: afterStateCheck, - lastActions: actionLogger.interestingActionSummaries, - time: Date.now(), - id: generateReportID(), - }, - ]; -} - function markDeletedEntries( entryInfos: { +[id: string]: RawEntryInfo }, deletedEntryIDs: $ReadOnlyArray, diff --git a/lib/reducers/thread-reducer.js b/lib/reducers/thread-reducer.js --- a/lib/reducers/thread-reducer.js +++ b/lib/reducers/thread-reducer.js @@ -1,7 +1,5 @@ // @flow -import _isEqual from 'lodash/fp/isEqual.js'; - import { setThreadUnreadStatusActionTypes, updateActivityActionTypes, @@ -31,12 +29,10 @@ type ThreadStoreOperation, threadStoreOpsHandlers, } from '../ops/thread-store-ops.js'; +import { stateSyncSpecs } from '../shared/state-sync/state-sync-specs.js'; import { updateSpecs } from '../shared/updates/update-specs.js'; import type { BaseAction } from '../types/redux-types.js'; -import { - type ClientThreadInconsistencyReportCreationRequest, - reportTypes, -} from '../types/report-types.js'; +import { type ClientThreadInconsistencyReportCreationRequest } from '../types/report-types.js'; import { serverRequestTypes, processServerRequestsActionType, @@ -50,11 +46,7 @@ type ClientUpdateInfo, processUpdatesActionType, } from '../types/update-types.js'; -import { actionLogger } from '../utils/action-logger.js'; import { setNewSessionActionType } from '../utils/action-utils.js'; -import { getConfig } from '../utils/config.js'; -import { generateReportID } from '../utils/report-utils.js'; -import { sanitizeActionSecrets } from '../utils/sanitization.js'; const { processStoreOperations: processThreadStoreOperations } = threadStoreOpsHandlers; @@ -77,28 +69,6 @@ .flat(); } -function findInconsistencies( - action: BaseAction, - beforeStateCheck: { +[id: string]: RawThreadInfo }, - afterStateCheck: { +[id: string]: RawThreadInfo }, -): ClientThreadInconsistencyReportCreationRequest[] { - if (_isEqual(beforeStateCheck)(afterStateCheck)) { - return []; - } - return [ - { - type: reportTypes.THREAD_INCONSISTENCY, - platformDetails: getConfig().platformDetails, - beforeAction: beforeStateCheck, - action: sanitizeActionSecrets(action), - pushResult: afterStateCheck, - lastActions: actionLogger.interestingActionSummaries, - time: Date.now(), - id: generateReportID(), - }, - ]; -} - function reduceThreadInfos( state: ThreadStore, action: BaseAction, @@ -310,11 +280,12 @@ threadStoreOperations, ); - const newThreadInconsistencies = findInconsistencies( - action, - state.threadInfos, - updatedThreadStore.threadInfos, - ); + const newThreadInconsistencies = + stateSyncSpecs.threads.findStoreInconsistencies( + action, + state.threadInfos, + updatedThreadStore.threadInfos, + ); return { threadStore: updatedThreadStore, diff --git a/lib/reducers/user-reducer.js b/lib/reducers/user-reducer.js --- a/lib/reducers/user-reducer.js +++ b/lib/reducers/user-reducer.js @@ -17,12 +17,9 @@ updateUserAvatarActionTypes, resetUserStateActionType, } from '../actions/user-actions.js'; +import { stateSyncSpecs } from '../shared/state-sync/state-sync-specs.js'; import { updateSpecs } from '../shared/updates/update-specs.js'; import type { BaseAction } from '../types/redux-types.js'; -import { - type UserInconsistencyReportCreationRequest, - reportTypes, -} from '../types/report-types.js'; import { serverRequestTypes, processServerRequestsActionType, @@ -33,16 +30,8 @@ } from '../types/socket-types.js'; import { updateTypes } from '../types/update-types-enum.js'; import { processUpdatesActionType } from '../types/update-types.js'; -import type { - CurrentUserInfo, - UserStore, - UserInfos, -} from '../types/user-types.js'; -import { actionLogger } from '../utils/action-logger.js'; +import type { CurrentUserInfo, UserStore } from '../types/user-types.js'; import { setNewSessionActionType } from '../utils/action-utils.js'; -import { getConfig } from '../utils/config.js'; -import { generateReportID } from '../utils/report-utils.js'; -import { sanitizeActionSecrets } from '../utils/sanitization.js'; function reduceCurrentUserInfo( state: ?CurrentUserInfo, @@ -130,28 +119,6 @@ return state; } -function findInconsistencies( - action: BaseAction, - beforeStateCheck: UserInfos, - afterStateCheck: UserInfos, -): UserInconsistencyReportCreationRequest[] { - if (_isEqual(beforeStateCheck)(afterStateCheck)) { - return []; - } - return [ - { - type: reportTypes.USER_INCONSISTENCY, - platformDetails: getConfig().platformDetails, - action: sanitizeActionSecrets(action), - beforeStateCheck, - afterStateCheck, - lastActions: actionLogger.interestingActionSummaries, - time: Date.now(), - id: generateReportID(), - }, - ]; -} - function reduceUserInfos(state: UserStore, action: BaseAction): UserStore { if ( action.type === joinThreadActionTypes.success || @@ -242,7 +209,7 @@ } } - const newInconsistencies = findInconsistencies( + const newInconsistencies = stateSyncSpecs.users.findStoreInconsistencies( action, state.userInfos, newUserInfos, diff --git a/lib/shared/state-sync/current-user-state-sync-spec.js b/lib/shared/state-sync/current-user-state-sync-spec.js --- a/lib/shared/state-sync/current-user-state-sync-spec.js +++ b/lib/shared/state-sync/current-user-state-sync-spec.js @@ -11,6 +11,7 @@ export const currentUserStateSyncSpec: StateSyncSpec< CurrentUserInfo, CurrentUserInfo, + void, > = Object.freeze({ hashKey: 'currentUserInfo', convertClientToServerInfos(info: CurrentUserInfo) { @@ -20,4 +21,7 @@ info, ); }, + findStoreInconsistencies() { + return undefined; + }, }); diff --git a/lib/shared/state-sync/entries-state-sync-spec.js b/lib/shared/state-sync/entries-state-sync-spec.js --- a/lib/shared/state-sync/entries-state-sync-spec.js +++ b/lib/shared/state-sync/entries-state-sync-spec.js @@ -1,5 +1,6 @@ // @flow +import _isEqual from 'lodash/fp/isEqual.js'; import t from 'tcomb'; import type { StateSyncSpec } from './state-sync-spec.js'; @@ -9,35 +10,83 @@ rawEntryInfoValidator, type RawEntryInfo, } from '../../types/entry-types.js'; +import { + reportTypes, + type ClientEntryInconsistencyReportCreationRequest, +} from '../../types/report-types.js'; +import type { ProcessServerRequestAction } from '../../types/request-types.js'; +import { actionLogger } from '../../utils/action-logger.js'; +import { getConfig } from '../../utils/config.js'; import { convertClientIDsToServerIDs } from '../../utils/conversion-utils.js'; import { values } from '../../utils/objects.js'; +import { generateReportID } from '../../utils/report-utils.js'; +import { sanitizeActionSecrets } from '../../utils/sanitization.js'; import { ashoatKeyserverID, tID } from '../../utils/validation-utils.js'; import { filterRawEntryInfosByCalendarQuery, serverEntryInfosObject, } from '../entry-utils.js'; -export const entriesStateSyncSpec: StateSyncSpec = - Object.freeze({ - hashKey: 'entryInfos', - innerHashSpec: { - hashKey: 'entryInfo', - deleteKey: 'deleteEntryIDs', - rawInfosKey: 'rawEntryInfos', - }, - convertClientToServerInfos( - infos: RawEntryInfos, - calendarQuery: CalendarQuery, - ) { - const filteredEntryInfos = filterRawEntryInfosByCalendarQuery( - serverEntryInfosObject(values(infos)), +export const entriesStateSyncSpec: StateSyncSpec< + RawEntryInfos, + RawEntryInfo, + Array, +> = Object.freeze({ + hashKey: 'entryInfos', + innerHashSpec: { + hashKey: 'entryInfo', + deleteKey: 'deleteEntryIDs', + rawInfosKey: 'rawEntryInfos', + }, + convertClientToServerInfos( + infos: RawEntryInfos, + calendarQuery: CalendarQuery, + ) { + const filteredEntryInfos = filterRawEntryInfosByCalendarQuery( + serverEntryInfosObject(values(infos)), + calendarQuery, + ); + + return convertClientIDsToServerIDs( + ashoatKeyserverID, + t.dict(tID, rawEntryInfoValidator), + filteredEntryInfos, + ); + }, + findStoreInconsistencies( + action: ProcessServerRequestAction, + beforeStateCheck: RawEntryInfos, + afterStateCheck: RawEntryInfos, + ) { + const calendarQuery = action.payload.calendarQuery; + // We don't want to bother reporting an inconsistency if it's just because + // of extraneous EntryInfos (not within the current calendarQuery) on either + // side + const filteredBeforeResult = filterRawEntryInfosByCalendarQuery( + serverEntryInfosObject(values(beforeStateCheck)), + calendarQuery, + ); + const filteredAfterResult = filterRawEntryInfosByCalendarQuery( + serverEntryInfosObject(values(afterStateCheck)), + calendarQuery, + ); + if (_isEqual(filteredBeforeResult)(filteredAfterResult)) { + return emptyArray; + } + return [ + { + type: reportTypes.ENTRY_INCONSISTENCY, + platformDetails: getConfig().platformDetails, + beforeAction: beforeStateCheck, + action: sanitizeActionSecrets(action), calendarQuery, - ); + pushResult: afterStateCheck, + lastActions: actionLogger.interestingActionSummaries, + time: Date.now(), + id: generateReportID(), + }, + ]; + }, +}); - return convertClientIDsToServerIDs( - ashoatKeyserverID, - t.dict(tID, rawEntryInfoValidator), - filteredEntryInfos, - ); - }, - }); +const emptyArray = []; diff --git a/lib/shared/state-sync/state-sync-spec.js b/lib/shared/state-sync/state-sync-spec.js --- a/lib/shared/state-sync/state-sync-spec.js +++ b/lib/shared/state-sync/state-sync-spec.js @@ -1,8 +1,9 @@ // @flow import type { CalendarQuery } from '../../types/entry-types.js'; +import type { ProcessServerRequestAction } from '../../types/request-types.js'; -export type StateSyncSpec = { +export type StateSyncSpec = { +hashKey: string, +innerHashSpec?: { +hashKey: string, @@ -14,4 +15,9 @@ infos: Infos, calendarQuery: CalendarQuery, ) => Infos, + +findStoreInconsistencies: ( + action: ProcessServerRequestAction, + beforeStateCheck: Infos, + afterStateCheck: Infos, + ) => Inconsistencies, }; diff --git a/lib/shared/state-sync/state-sync-specs.js b/lib/shared/state-sync/state-sync-specs.js --- a/lib/shared/state-sync/state-sync-specs.js +++ b/lib/shared/state-sync/state-sync-specs.js @@ -14,5 +14,5 @@ }); (stateSyncSpecs: { - +[string]: StateSyncSpec, + +[string]: StateSyncSpec, }); diff --git a/lib/shared/state-sync/threads-state-sync-spec.js b/lib/shared/state-sync/threads-state-sync-spec.js --- a/lib/shared/state-sync/threads-state-sync-spec.js +++ b/lib/shared/state-sync/threads-state-sync-spec.js @@ -1,19 +1,30 @@ // @flow +import _isEqual from 'lodash/fp/isEqual.js'; import t from 'tcomb'; import type { StateSyncSpec } from './state-sync-spec.js'; +import { + reportTypes, + type ClientThreadInconsistencyReportCreationRequest, +} from '../../types/report-types.js'; +import type { ProcessServerRequestAction } from '../../types/request-types.js'; import { type RawThreadInfos, type RawThreadInfo, rawThreadInfoValidator, } from '../../types/thread-types.js'; +import { actionLogger } from '../../utils/action-logger.js'; +import { getConfig } from '../../utils/config.js'; import { convertClientIDsToServerIDs } from '../../utils/conversion-utils.js'; +import { generateReportID } from '../../utils/report-utils.js'; +import { sanitizeActionSecrets } from '../../utils/sanitization.js'; import { ashoatKeyserverID, tID } from '../../utils/validation-utils.js'; export const threadsStateSyncSpec: StateSyncSpec< RawThreadInfos, RawThreadInfo, + Array, > = Object.freeze({ hashKey: 'threadInfos', innerHashSpec: { @@ -28,4 +39,27 @@ infos, ); }, + findStoreInconsistencies( + action: ProcessServerRequestAction, + beforeStateCheck: RawThreadInfos, + afterStateCheck: RawThreadInfos, + ) { + if (_isEqual(beforeStateCheck)(afterStateCheck)) { + return emptyArray; + } + return [ + { + type: reportTypes.THREAD_INCONSISTENCY, + platformDetails: getConfig().platformDetails, + beforeAction: beforeStateCheck, + action: sanitizeActionSecrets(action), + pushResult: afterStateCheck, + lastActions: actionLogger.interestingActionSummaries, + time: Date.now(), + id: generateReportID(), + }, + ]; + }, }); + +const emptyArray = []; diff --git a/lib/shared/state-sync/users-state-sync-spec.js b/lib/shared/state-sync/users-state-sync-spec.js --- a/lib/shared/state-sync/users-state-sync-spec.js +++ b/lib/shared/state-sync/users-state-sync-spec.js @@ -1,30 +1,65 @@ // @flow +import _isEqual from 'lodash/fp/isEqual.js'; + import type { StateSyncSpec } from './state-sync-spec.js'; +import { + reportTypes, + type UserInconsistencyReportCreationRequest, +} from '../../types/report-types.js'; +import type { ProcessServerRequestAction } from '../../types/request-types.js'; import { type UserInfo, type UserInfos, userInfosValidator, } from '../../types/user-types.js'; +import { actionLogger } from '../../utils/action-logger.js'; +import { getConfig } from '../../utils/config.js'; import { convertClientIDsToServerIDs } from '../../utils/conversion-utils.js'; +import { generateReportID } from '../../utils/report-utils.js'; +import { sanitizeActionSecrets } from '../../utils/sanitization.js'; import { ashoatKeyserverID } from '../../utils/validation-utils.js'; -export const usersStateSyncSpec: StateSyncSpec = - Object.freeze({ - hashKey: 'userInfos', - innerHashSpec: { - hashKey: 'userInfo', - deleteKey: 'deleteUserInfoIDs', - rawInfosKey: 'userInfos', - additionalDeleteCondition(user: UserInfo) { - return !user.username; - }, +export const usersStateSyncSpec: StateSyncSpec< + UserInfos, + UserInfo, + Array, +> = Object.freeze({ + hashKey: 'userInfos', + innerHashSpec: { + hashKey: 'userInfo', + deleteKey: 'deleteUserInfoIDs', + rawInfosKey: 'userInfos', + additionalDeleteCondition(user: UserInfo) { + return !user.username; }, - convertClientToServerInfos(infos: UserInfos) { - return convertClientIDsToServerIDs( - ashoatKeyserverID, - userInfosValidator, - infos, - ); - }, - }); + }, + convertClientToServerInfos(infos: UserInfos) { + return convertClientIDsToServerIDs( + ashoatKeyserverID, + userInfosValidator, + infos, + ); + }, + findStoreInconsistencies( + action: ProcessServerRequestAction, + beforeStateCheck: UserInfos, + afterStateCheck: UserInfos, + ) { + if (_isEqual(beforeStateCheck)(afterStateCheck)) { + return []; + } + return [ + { + type: reportTypes.USER_INCONSISTENCY, + platformDetails: getConfig().platformDetails, + action: sanitizeActionSecrets(action), + beforeStateCheck, + afterStateCheck, + lastActions: actionLogger.interestingActionSummaries, + time: Date.now(), + id: generateReportID(), + }, + ]; + }, +}); diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js --- a/lib/types/redux-types.js +++ b/lib/types/redux-types.js @@ -83,7 +83,7 @@ ClientReportCreationRequest, } from './report-types.js'; import type { - ProcessServerRequestsPayload, + ProcessServerRequestAction, GetOlmSessionInitializationDataResponse, } from './request-types.js'; import type { @@ -778,10 +778,7 @@ +type: 'INCREMENTAL_STATE_SYNC', +payload: StateSyncIncrementalActionPayload, } - | { - +type: 'PROCESS_SERVER_REQUESTS', - +payload: ProcessServerRequestsPayload, - } + | ProcessServerRequestAction | { +type: 'UPDATE_CONNECTION_STATUS', +payload: UpdateConnectionStatusPayload, diff --git a/lib/types/request-types.js b/lib/types/request-types.js --- a/lib/types/request-types.js +++ b/lib/types/request-types.js @@ -272,6 +272,10 @@ +serverRequests: $ReadOnlyArray, +calendarQuery: CalendarQuery, }; +export type ProcessServerRequestAction = { + +type: 'PROCESS_SERVER_REQUESTS', + +payload: ProcessServerRequestsPayload, +}; export type GetSessionPublicKeysArgs = { +session: string,