Page MenuHomePhabricator

D12366.diff
No OneTemporary

D12366.diff

diff --git a/lib/actions/update-actions.js b/lib/actions/update-actions.js
new file mode 100644
--- /dev/null
+++ b/lib/actions/update-actions.js
@@ -0,0 +1,40 @@
+// @flow
+
+import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js';
+import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js';
+import { permissionsAndAuthRelatedRequestTimeout } from '../shared/timeouts.js';
+import type { FetchPendingUpdatesInput } from '../types/session-types.js';
+import type { ClientStateSyncSocketResult } from '../types/socket-types.js';
+
+const fetchPendingUpdatesActionTypes = Object.freeze({
+ started: 'FETCH_PENDING_UPDATES_STARTED',
+ success: 'FETCH_PENDING_UPDATES_SUCCESS',
+ failed: 'FETCH_PENDING_UPDATES_FAILED',
+});
+const fetchPendingUpdatesCallKeyserverEndpointOptions = {
+ timeout: permissionsAndAuthRelatedRequestTimeout,
+};
+const fetchPendingUpdates =
+ (
+ callKeyserverEndpoint: CallKeyserverEndpoint,
+ ): ((
+ input: FetchPendingUpdatesInput,
+ ) => Promise<ClientStateSyncSocketResult>) =>
+ async input => {
+ const { keyserverID, ...sessionState } = input;
+ const requests = { [keyserverID]: sessionState };
+ const responses = await callKeyserverEndpoint(
+ 'fetch_pending_updates',
+ requests,
+ fetchPendingUpdatesCallKeyserverEndpointOptions,
+ );
+ return { keyserverID, ...responses[keyserverID] };
+ };
+
+function useFetchPendingUpdates(): (
+ input: FetchPendingUpdatesInput,
+) => Promise<ClientStateSyncSocketResult> {
+ return useKeyserverCall(fetchPendingUpdates);
+}
+
+export { fetchPendingUpdatesActionTypes, useFetchPendingUpdates };
diff --git a/lib/reducers/calendar-filters-reducer.js b/lib/reducers/calendar-filters-reducer.js
--- a/lib/reducers/calendar-filters-reducer.js
+++ b/lib/reducers/calendar-filters-reducer.js
@@ -11,6 +11,7 @@
leaveThreadActionTypes,
deleteThreadActionTypes,
} from '../actions/thread-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
keyserverAuthActionTypes,
deleteKeyserverAccountActionTypes,
@@ -38,6 +39,7 @@
import {
fullStateSyncActionType,
incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
} from '../types/socket-types.js';
import type { RawThreadInfos, ThreadStore } from '../types/thread-types.js';
import {
@@ -114,11 +116,27 @@
state,
action.payload.updatesResult.newUpdates,
);
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.INCREMENTAL
+ ) {
+ return updateFilterListFromUpdateInfos(
+ state,
+ action.payload.updatesResult.newUpdates,
+ );
} else if (action.type === fullStateSyncActionType) {
return removeDeletedThreadIDsFromFilterList(
state,
action.payload.threadInfos,
);
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL
+ ) {
+ return removeDeletedThreadIDsFromFilterList(
+ state,
+ action.payload.threadInfos,
+ );
} else if (action.type === updateCalendarCommunityFilter) {
const nonThreadFilters = nonThreadCalendarFilters(state);
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
@@ -33,6 +33,7 @@
changeThreadMemberRolesActionTypes,
newThreadActionTypes,
} from '../actions/thread-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
keyserverAuthActionTypes,
deleteKeyserverAccountActionTypes,
@@ -56,6 +57,9 @@
import {
fullStateSyncActionType,
incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
+ type ClientStateSyncIncrementalSocketResult,
+ type StateSyncIncrementalActionPayload,
} from '../types/socket-types.js';
import type { RawThreadInfos } from '../types/thread-types.js';
import {
@@ -187,16 +191,49 @@
return ops;
}
+type ReduceEntryInfosResult = {
+ +entryStore: EntryStore,
+ +entryStoreOperations: $ReadOnlyArray<EntryStoreOperation>,
+ +reportCreationRequests: $ReadOnlyArray<ClientEntryInconsistencyReportCreationRequest>,
+};
+
+function handleIncrementalStateSync(
+ entryStore: EntryStore,
+ newThreadInfos: RawThreadInfos,
+ payload:
+ | ClientStateSyncIncrementalSocketResult
+ | StateSyncIncrementalActionPayload,
+): ReduceEntryInfosResult {
+ const { entryInfos, daysToEntries } = entryStore;
+ const { deletedEntryIDs, deltaEntryInfos, updatesResult } = payload;
+ const mergeEntriesOps = mergeNewEntryInfosOps(
+ entryInfos,
+ daysToEntries,
+ mergeUpdateEntryInfos(deltaEntryInfos, updatesResult.newUpdates),
+ newThreadInfos,
+ );
+ const updatedEntryInfos = entryStoreOpsHandlers.processStoreOperations(
+ entryStore,
+ mergeEntriesOps,
+ ).entryInfos;
+ const markAsDeletedOps = markDeletedEntries(
+ updatedEntryInfos,
+ deletedEntryIDs,
+ );
+ const ops = [...mergeEntriesOps, ...markAsDeletedOps];
+ return {
+ entryStore: entryStoreOpsHandlers.processStoreOperations(entryStore, ops),
+ entryStoreOperations: ops,
+ reportCreationRequests: [],
+ };
+}
+
function reduceEntryInfos(
entryStore: EntryStore,
action: BaseAction,
newThreadInfos: RawThreadInfos,
onStateDifference?: (message: string) => mixed,
-): {
- +entryStore: EntryStore,
- +entryStoreOperations: $ReadOnlyArray<EntryStoreOperation>,
- +reportCreationRequests: $ReadOnlyArray<ClientEntryInconsistencyReportCreationRequest>,
-} {
+): ReduceEntryInfosResult {
const { entryInfos, daysToEntries, lastUserInteractionCalendar } = entryStore;
if (
action.type === deleteKeyserverAccountActionTypes.success ||
@@ -570,29 +607,31 @@
};
}
} else if (action.type === incrementalStateSyncActionType) {
- const mergeEntriesOps = mergeNewEntryInfosOps(
- entryInfos,
- daysToEntries,
- mergeUpdateEntryInfos(
- action.payload.deltaEntryInfos,
- action.payload.updatesResult.newUpdates,
- ),
- newThreadInfos,
- );
- const updatedEntryInfos = entryStoreOpsHandlers.processStoreOperations(
+ return handleIncrementalStateSync(
entryStore,
- mergeEntriesOps,
- ).entryInfos;
- const markAsDeletedOps = markDeletedEntries(
- updatedEntryInfos,
- action.payload.deletedEntryIDs,
+ newThreadInfos,
+ action.payload,
);
- const ops = [...mergeEntriesOps, ...markAsDeletedOps];
- return {
- entryStore: entryStoreOpsHandlers.processStoreOperations(entryStore, ops),
- entryStoreOperations: ops,
- reportCreationRequests: [],
- };
+ } else if (action.type === fetchPendingUpdatesActionTypes.success) {
+ const { payload } = action;
+ if (payload.type === stateSyncPayloadTypes.INCREMENTAL) {
+ return handleIncrementalStateSync(entryStore, newThreadInfos, payload);
+ } else {
+ const ops = mergeNewEntryInfosOps(
+ entryInfos,
+ daysToEntries,
+ payload.rawEntryInfos,
+ newThreadInfos,
+ );
+ return {
+ entryStore: entryStoreOpsHandlers.processStoreOperations(
+ entryStore,
+ ops,
+ ),
+ entryStoreOperations: ops,
+ reportCreationRequests: [],
+ };
+ }
} else if (
action.type === processUpdatesActionType ||
action.type === joinThreadActionTypes.success ||
diff --git a/lib/reducers/integrity-reducer.js b/lib/reducers/integrity-reducer.js
--- a/lib/reducers/integrity-reducer.js
+++ b/lib/reducers/integrity-reducer.js
@@ -3,6 +3,7 @@
import { setClientDBStoreActionType } from '../actions/client-db-store-actions.js';
import { updateIntegrityStoreActionType } from '../actions/integrity-actions.js';
import { legacySiweAuthActionTypes } from '../actions/siwe-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
keyserverAuthActionTypes,
legacyLogInActionTypes,
@@ -17,7 +18,10 @@
import type { IntegrityStore, ThreadHashes } from '../types/integrity-types';
import type { RawThreadInfo } from '../types/minimally-encoded-thread-permissions-types.js';
import type { BaseAction } from '../types/redux-types.js';
-import { fullStateSyncActionType } from '../types/socket-types.js';
+import {
+ fullStateSyncActionType,
+ stateSyncPayloadTypes,
+} from '../types/socket-types.js';
import { getMessageForException } from '../utils/errors.js';
import { assertObjectsAreEqual, hash } from '../utils/objects.js';
@@ -60,7 +64,11 @@
+integrityStore: IntegrityStore,
+integrityStoreOperations: $ReadOnlyArray<IntegrityStoreOperation>,
} {
- if (action.type === fullStateSyncActionType) {
+ if (
+ action.type === fullStateSyncActionType ||
+ (action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL)
+ ) {
const removeAllOperation = { type: 'remove_all_integrity_thread_hashes' };
const threadHashesArray = Object.entries(state.threadHashes).filter(
([key]) => extractKeyserverIDFromID(key) !== action.payload.keyserverID,
diff --git a/lib/reducers/keyserver-reducer.js b/lib/reducers/keyserver-reducer.js
--- a/lib/reducers/keyserver-reducer.js
+++ b/lib/reducers/keyserver-reducer.js
@@ -14,6 +14,7 @@
removeKeyserverActionType,
} from '../actions/keyserver-actions.js';
import { legacySiweAuthActionTypes } from '../actions/siwe-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
identityLogInActionTypes,
identityRegisterActionTypes,
@@ -50,6 +51,9 @@
import {
fullStateSyncActionType,
incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
+ type ClientStateSyncIncrementalSocketResult,
+ type StateSyncIncrementalActionPayload,
} from '../types/socket-types.js';
import { updateTypes } from '../types/update-types-enum.js';
import { processUpdatesActionType } from '../types/update-types.js';
@@ -84,6 +88,24 @@
}
}
+function shouldClearDeviceToken(
+ state: KeyserverStore,
+ payload:
+ | ClientStateSyncIncrementalSocketResult
+ | StateSyncIncrementalActionPayload,
+): boolean {
+ const { keyserverID, updatesResult } = payload;
+ for (const update of updatesResult.newUpdates) {
+ if (
+ update.type === updateTypes.BAD_DEVICE_TOKEN &&
+ update.deviceToken === state.keyserverInfos[keyserverID].deviceToken
+ ) {
+ return true;
+ }
+ }
+ return false;
+}
+
const { processStoreOperations: processStoreOps } = keyserverStoreOpsHandlers;
export default function reduceKeyserverStore(
@@ -245,31 +267,69 @@
keyserverStore: processStoreOps(state, [operation]),
keyserverStoreOperations: [operation],
};
- } else if (action.type === incrementalStateSyncActionType) {
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL
+ ) {
const { keyserverID } = action.payload;
- let { deviceToken } = state.keyserverInfos[keyserverID];
- for (const update of action.payload.updatesResult.newUpdates) {
- if (
- update.type === updateTypes.BAD_DEVICE_TOKEN &&
- update.deviceToken === state.keyserverInfos[keyserverID].deviceToken
- ) {
- deviceToken = null;
- break;
- }
- }
const operation: ReplaceKeyserverOperation = {
type: 'replace_keyserver',
payload: {
id: keyserverID,
keyserverInfo: {
...state.keyserverInfos[keyserverID],
- actualizedCalendarQuery: action.payload.calendarQuery,
- updatesCurrentAsOf: action.payload.updatesResult.currentAsOf,
+ updatesCurrentAsOf: action.payload.updatesCurrentAsOf,
+ },
+ },
+ };
+
+ return {
+ keyserverStore: processStoreOps(state, [operation]),
+ keyserverStoreOperations: [operation],
+ };
+ } else if (action.type === incrementalStateSyncActionType) {
+ const { payload } = action;
+ const { keyserverID } = payload;
+ const deviceToken = shouldClearDeviceToken(state, payload)
+ ? null
+ : state.keyserverInfos[keyserverID].deviceToken;
+ const operation: ReplaceKeyserverOperation = {
+ type: 'replace_keyserver',
+ payload: {
+ id: keyserverID,
+ keyserverInfo: {
+ ...state.keyserverInfos[keyserverID],
+ actualizedCalendarQuery: payload.calendarQuery,
+ updatesCurrentAsOf: payload.updatesResult.currentAsOf,
deviceToken,
},
},
};
+ return {
+ keyserverStore: processStoreOps(state, [operation]),
+ keyserverStoreOperations: [operation],
+ };
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.INCREMENTAL
+ ) {
+ const { payload } = action;
+ const { keyserverID } = payload;
+ const deviceToken = shouldClearDeviceToken(state, payload)
+ ? null
+ : state.keyserverInfos[keyserverID].deviceToken;
+ const operation: ReplaceKeyserverOperation = {
+ type: 'replace_keyserver',
+ payload: {
+ id: keyserverID,
+ keyserverInfo: {
+ ...state.keyserverInfos[keyserverID],
+ updatesCurrentAsOf: payload.updatesResult.currentAsOf,
+ deviceToken,
+ },
+ },
+ };
return {
keyserverStore: processStoreOps(state, [operation]),
keyserverStoreOperations: [operation],
diff --git a/lib/reducers/master-reducer.js b/lib/reducers/master-reducer.js
--- a/lib/reducers/master-reducer.js
+++ b/lib/reducers/master-reducer.js
@@ -26,6 +26,7 @@
import { reduceCurrentUserInfo, reduceUserInfos } from './user-reducer.js';
import { addKeyserverActionType } from '../actions/keyserver-actions.js';
import { legacySiweAuthActionTypes } from '../actions/siwe-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
legacyKeyserverRegisterActionTypes,
legacyLogInActionTypes,
@@ -97,6 +98,7 @@
if (
action.type !== incrementalStateSyncActionType &&
action.type !== fullStateSyncActionType &&
+ action.type !== fetchPendingUpdatesActionTypes.success &&
action.type !== legacyKeyserverRegisterActionTypes.success &&
action.type !== legacyLogInActionTypes.success &&
action.type !== legacySiweAuthActionTypes.success &&
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
@@ -45,6 +45,7 @@
changeThreadMemberRolesActionTypes,
joinThreadActionTypes,
} from '../actions/thread-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import { updateMultimediaMessageMediaActionType } from '../actions/upload-actions.js';
import {
keyserverAuthActionTypes,
@@ -96,6 +97,7 @@
import {
fullStateSyncActionType,
incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
} from '../types/socket-types.js';
import { threadPermissions } from '../types/thread-permission-types.js';
import type {
@@ -778,23 +780,48 @@
newThreadInfos,
);
} else if (action.type === incrementalStateSyncActionType) {
+ const { messagesResult, updatesResult } = action.payload;
if (
- action.payload.messagesResult.rawMessageInfos.length === 0 &&
- action.payload.updatesResult.newUpdates.length === 0
+ messagesResult.rawMessageInfos.length === 0 &&
+ updatesResult.newUpdates.length === 0
) {
return { messageStoreOperations: [], messageStore };
}
- const messagesResult = mergeUpdatesWithMessageInfos(
- action.payload.messagesResult.rawMessageInfos,
- action.payload.updatesResult.newUpdates,
- action.payload.messagesResult.truncationStatuses,
+ const newMessagesResult = mergeUpdatesWithMessageInfos(
+ messagesResult.rawMessageInfos,
+ updatesResult.newUpdates,
+ messagesResult.truncationStatuses,
);
return mergeNewMessages(
messageStore,
+ newMessagesResult.rawMessageInfos,
+ newMessagesResult.truncationStatuses,
+ newThreadInfos,
+ );
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.INCREMENTAL
+ ) {
+ const { messagesResult, updatesResult } = action.payload;
+ if (
+ messagesResult.rawMessageInfos.length === 0 &&
+ updatesResult.newUpdates.length === 0
+ ) {
+ return { messageStoreOperations: [], messageStore };
+ }
+
+ const newMessagesResult = mergeUpdatesWithMessageInfos(
messagesResult.rawMessageInfos,
+ updatesResult.newUpdates,
messagesResult.truncationStatuses,
+ );
+
+ return mergeNewMessages(
+ messageStore,
+ newMessagesResult.rawMessageInfos,
+ newMessagesResult.truncationStatuses,
newThreadInfos,
);
} else if (action.type === processUpdatesActionType) {
@@ -825,7 +852,9 @@
};
} else if (
action.type === fullStateSyncActionType ||
- action.type === processMessagesActionType
+ action.type === processMessagesActionType ||
+ (action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL)
) {
const { messagesResult } = action.payload;
return mergeNewMessages(
diff --git a/lib/reducers/thread-activity-reducer.js b/lib/reducers/thread-activity-reducer.js
--- a/lib/reducers/thread-activity-reducer.js
+++ b/lib/reducers/thread-activity-reducer.js
@@ -15,6 +15,7 @@
newThreadActionTypes,
removeUsersFromThreadActionTypes,
} from '../actions/thread-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js';
import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js';
@@ -24,7 +25,10 @@
} from '../ops/thread-activity-store-ops.js';
import { isWebPlatform } from '../types/device-types.js';
import type { BaseAction } from '../types/redux-types.js';
-import { incrementalStateSyncActionType } from '../types/socket-types.js';
+import {
+ incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
+} from '../types/socket-types.js';
import type { ThreadActivityStore } from '../types/thread-activity-types.js';
import { updateThreadLastNavigatedActionType } from '../types/thread-activity-types.js';
import { updateTypes } from '../types/update-types-enum.js';
@@ -59,6 +63,52 @@
}
}
+type ReduceThreadActivityResult = {
+ +threadActivityStore: ThreadActivityStore,
+ +threadActivityStoreOperations: $ReadOnlyArray<ThreadActivityStoreOperation>,
+};
+
+function handleThreadDeletionUpdates(
+ state: ThreadActivityStore,
+ newUpdates: $ReadOnlyArray<ClientUpdateInfo>,
+): ReduceThreadActivityResult {
+ if (newUpdates.length === 0) {
+ return {
+ threadActivityStore: state,
+ threadActivityStoreOperations: [],
+ };
+ }
+
+ const deleteThreadUpdates = newUpdates.filter(
+ (update: ClientUpdateInfo) => update.type === updateTypes.DELETE_THREAD,
+ );
+ if (deleteThreadUpdates.length === 0) {
+ return {
+ threadActivityStore: state,
+ threadActivityStoreOperations: [],
+ };
+ }
+
+ const threadIDsToRemove = [];
+ for (const update: ClientUpdateInfo of deleteThreadUpdates) {
+ invariant(
+ update.type === updateTypes.DELETE_THREAD,
+ 'update must be of type DELETE_THREAD',
+ );
+ threadIDsToRemove.push(update.threadID);
+ }
+ const removeOperation = {
+ type: 'remove_thread_activity_entries',
+ payload: {
+ ids: threadIDsToRemove,
+ },
+ };
+ return {
+ threadActivityStore: processStoreOps(state, [removeOperation]),
+ threadActivityStoreOperations: [removeOperation],
+ };
+}
+
const { processStoreOperations: processStoreOps } =
threadActivityStoreOpsHandlers;
@@ -66,10 +116,7 @@
state: ThreadActivityStore,
action: BaseAction,
onStateDifference?: (message: string) => mixed,
-): {
- +threadActivityStore: ThreadActivityStore,
- +threadActivityStoreOperations: $ReadOnlyArray<ThreadActivityStoreOperation>,
-} {
+): ReduceThreadActivityResult {
if (action.type === updateThreadLastNavigatedActionType) {
const { threadID, time } = action.payload;
const replaceOperation = {
@@ -119,42 +166,18 @@
action.type === modifyCommunityRoleActionTypes.success ||
action.type === deleteCommunityRoleActionTypes.success
) {
- const { newUpdates } = action.payload.updatesResult;
- if (newUpdates.length === 0) {
- return {
- threadActivityStore: state,
- threadActivityStoreOperations: [],
- };
- }
-
- const deleteThreadUpdates = newUpdates.filter(
- (update: ClientUpdateInfo) => update.type === updateTypes.DELETE_THREAD,
+ return handleThreadDeletionUpdates(
+ state,
+ action.payload.updatesResult.newUpdates,
+ );
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.INCREMENTAL
+ ) {
+ return handleThreadDeletionUpdates(
+ state,
+ action.payload.updatesResult.newUpdates,
);
- if (deleteThreadUpdates.length === 0) {
- return {
- threadActivityStore: state,
- threadActivityStoreOperations: [],
- };
- }
-
- const threadIDsToRemove = [];
- for (const update: ClientUpdateInfo of deleteThreadUpdates) {
- invariant(
- update.type === updateTypes.DELETE_THREAD,
- 'update must be of type DELETE_THREAD',
- );
- threadIDsToRemove.push(update.threadID);
- }
- const removeOperation = {
- type: 'remove_thread_activity_entries',
- payload: {
- ids: threadIDsToRemove,
- },
- };
- return {
- threadActivityStore: processStoreOps(state, [removeOperation]),
- threadActivityStoreOperations: [removeOperation],
- };
} else if (action.type === deleteKeyserverAccountActionTypes.success) {
const threadIDsToRemove = [];
const keyserverIDsSet = new Set<string>(action.payload.keyserverIDs);
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
@@ -18,6 +18,7 @@
modifyCommunityRoleActionTypes,
deleteCommunityRoleActionTypes,
} from '../actions/thread-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
keyserverAuthActionTypes,
deleteKeyserverAccountActionTypes,
@@ -46,6 +47,7 @@
import {
fullStateSyncActionType,
incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
} from '../types/socket-types.js';
import type { RawThreadInfos, ThreadStore } from '../types/thread-types.js';
import {
@@ -71,38 +73,60 @@
.flat();
}
-function reduceThreadInfos(
- state: ThreadStore,
- action: BaseAction,
-): {
+type ReduceThreadInfosResult = {
threadStore: ThreadStore,
newThreadInconsistencies: $ReadOnlyArray<ClientThreadInconsistencyReportCreationRequest>,
threadStoreOperations: $ReadOnlyArray<ThreadStoreOperation>,
-} {
+};
+
+function handleFullStateSync(
+ state: ThreadStore,
+ keyserverID: string,
+ newThreadInfos: RawThreadInfos,
+): ReduceThreadInfosResult {
+ const threadsToRemove = Object.keys(state.threadInfos).filter(
+ key => extractKeyserverIDFromID(key) === keyserverID,
+ );
+ const threadStoreOperations = [
+ {
+ type: 'remove',
+ payload: { ids: threadsToRemove },
+ },
+ ...Object.keys(newThreadInfos).map((id: string) => ({
+ type: 'replace',
+ payload: { id, threadInfo: newThreadInfos[id] },
+ })),
+ ];
+ const updatedThreadStore = processThreadStoreOperations(
+ state,
+ threadStoreOperations,
+ );
+ return {
+ threadStore: updatedThreadStore,
+ newThreadInconsistencies: [],
+ threadStoreOperations,
+ };
+}
+
+function reduceThreadInfos(
+ state: ThreadStore,
+ action: BaseAction,
+): ReduceThreadInfosResult {
if (action.type === fullStateSyncActionType) {
- const threadsToRemove = Object.keys(state.threadInfos).filter(
- key => extractKeyserverIDFromID(key) === action.payload.keyserverID,
+ return handleFullStateSync(
+ state,
+ action.payload.keyserverID,
+ action.payload.threadInfos,
);
- const newThreadInfos = action.payload.threadInfos;
- const threadStoreOperations = [
- {
- type: 'remove',
- payload: { ids: threadsToRemove },
- },
- ...Object.keys(newThreadInfos).map((id: string) => ({
- type: 'replace',
- payload: { id, threadInfo: newThreadInfos[id] },
- })),
- ];
- const updatedThreadStore = processThreadStoreOperations(
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL
+ ) {
+ return handleFullStateSync(
state,
- threadStoreOperations,
+ action.payload.keyserverID,
+ action.payload.threadInfos,
);
- return {
- threadStore: updatedThreadStore,
- newThreadInconsistencies: [],
- threadStoreOperations,
- };
} else if (
action.type === legacyLogInActionTypes.success ||
action.type === legacySiweAuthActionTypes.success ||
@@ -249,6 +273,31 @@
newThreadInconsistencies: [],
threadStoreOperations,
};
+ } else if (
+ action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.INCREMENTAL
+ ) {
+ const { newUpdates } = action.payload.updatesResult;
+ if (newUpdates.length === 0) {
+ return {
+ threadStore: state,
+ newThreadInconsistencies: [],
+ threadStoreOperations: [],
+ };
+ }
+ const threadStoreOperations = generateOpsForThreadUpdates(
+ state.threadInfos,
+ newUpdates,
+ );
+ const updatedThreadStore = processThreadStoreOperations(
+ state,
+ threadStoreOperations,
+ );
+ return {
+ threadStore: updatedThreadStore,
+ newThreadInconsistencies: [],
+ threadStoreOperations,
+ };
} else if (action.type === updateSubscriptionActionTypes.success) {
const { threadID, subscription } = action.payload;
const threadInfo = state.threadInfos[threadID];
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
@@ -9,6 +9,7 @@
joinThreadActionTypes,
newThreadActionTypes,
} from '../actions/thread-actions.js';
+import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
import {
findUserIdentitiesActionTypes,
processNewUserIDsActionType,
@@ -39,10 +40,16 @@
import {
fullStateSyncActionType,
incrementalStateSyncActionType,
+ stateSyncPayloadTypes,
+ type ClientStateSyncIncrementalSocketResult,
+ type StateSyncIncrementalActionPayload,
} from '../types/socket-types.js';
import { updateTypes } from '../types/update-types-enum.js';
-import { processUpdatesActionType } from '../types/update-types.js';
-import type { ClientUpdateInfo } from '../types/update-types.js';
+import {
+ processUpdatesActionType,
+ type ClientUpdateInfo,
+ type ClientUpdatesResultWithUserInfos,
+} from '../types/update-types.js';
import type {
CurrentUserInfo,
UserInfos,
@@ -54,6 +61,18 @@
usingCommServicesAccessToken,
} from '../utils/services-utils.js';
+function handleCurrentUserUpdates(
+ state: ?CurrentUserInfo,
+ newUpdates: $ReadOnlyArray<ClientUpdateInfo>,
+): ?CurrentUserInfo {
+ return newUpdates.reduce((reducedState, update) => {
+ const { reduceCurrentUser } = updateSpecs[update.type];
+ return reduceCurrentUser
+ ? reduceCurrentUser(reducedState, update)
+ : reducedState;
+ }, state);
+}
+
function reduceCurrentUserInfo(
state: ?CurrentUserInfo,
action: BaseAction,
@@ -107,7 +126,9 @@
}
}
} else if (
- action.type === fullStateSyncActionType &&
+ (action.type === fullStateSyncActionType ||
+ (action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL)) &&
relyingOnAuthoritativeKeyserver
) {
if (action.payload.keyserverID !== authoritativeKeyserverID()) {
@@ -125,15 +146,23 @@
if (action.payload.keyserverID !== authoritativeKeyserverID()) {
return state;
}
- return action.payload.updatesResult.newUpdates.reduce(
- (reducedState, update) => {
- const { reduceCurrentUser } = updateSpecs[update.type];
- return reduceCurrentUser
- ? reduceCurrentUser(reducedState, update)
- : reducedState;
- },
+ return handleCurrentUserUpdates(
state,
+ action.payload.updatesResult.newUpdates,
);
+ } else if (action.type === fetchPendingUpdatesActionTypes.success) {
+ if (!relyingOnAuthoritativeKeyserver) {
+ return state;
+ }
+ const { payload } = action;
+ if (payload.type !== stateSyncPayloadTypes.INCREMENTAL) {
+ return state;
+ }
+ const { newUpdates } = payload.updatesResult;
+ if (action.payload.keyserverID !== authoritativeKeyserverID()) {
+ return state;
+ }
+ return handleCurrentUserUpdates(state, newUpdates);
} else if (
action.type === processServerRequestsActionType &&
relyingOnAuthoritativeKeyserver
@@ -194,14 +223,51 @@
.flat();
}
-function reduceUserInfos(
- state: UserStore,
- action: BaseAction,
-): [
+type ReduceUserInfosResult = [
UserStore,
$ReadOnlyArray<ClientUserInconsistencyReportCreationRequest>,
$ReadOnlyArray<UserStoreOperation>,
-] {
+];
+
+function handleUserInfoUpdates(
+ state: UserStore,
+ payload:
+ | ClientStateSyncIncrementalSocketResult
+ | StateSyncIncrementalActionPayload
+ | ClientUpdatesResultWithUserInfos,
+): ReduceUserInfosResult {
+ if (payload.keyserverID !== authoritativeKeyserverID()) {
+ return [state, [], []];
+ }
+ const newUserInfos = _keyBy(userInfo => userInfo.id)(payload.userInfos);
+ const userStoreOps: $ReadOnlyArray<UserStoreOperation> = [
+ ...convertUserInfosToReplaceUserOps(newUserInfos),
+ ...generateOpsForUserUpdates(payload),
+ ];
+
+ const processedUserInfos: UserInfos = processUserStoreOps(
+ state.userInfos,
+ userStoreOps,
+ );
+
+ if (_isEqual(state.userInfos)(processedUserInfos)) {
+ return [state, [], []];
+ }
+
+ return [
+ {
+ ...state,
+ userInfos: processedUserInfos,
+ },
+ [],
+ userStoreOps,
+ ];
+}
+
+function reduceUserInfos(
+ state: UserStore,
+ action: BaseAction,
+): ReduceUserInfosResult {
if (action.type === processNewUserIDsActionType) {
const filteredUserIDs = action.payload.userIDs.filter(
id => !state.userInfos[id],
@@ -280,7 +346,9 @@
userStoreOps,
];
} else if (
- action.type === fullStateSyncActionType &&
+ (action.type === fullStateSyncActionType ||
+ (action.type === fetchPendingUpdatesActionTypes.success &&
+ action.payload.type === stateSyncPayloadTypes.FULL)) &&
relyingOnAuthoritativeKeyserver
) {
if (action.payload.keyserverID !== authoritativeKeyserverID()) {
@@ -358,31 +426,14 @@
action.type === processUpdatesActionType) &&
relyingOnAuthoritativeKeyserver
) {
- if (action.payload.keyserverID !== authoritativeKeyserverID()) {
+ return handleUserInfoUpdates(state, action.payload);
+ } else if (action.type === fetchPendingUpdatesActionTypes.success) {
+ if (!relyingOnAuthoritativeKeyserver) {
return [state, [], []];
}
- const newUserInfos = _keyBy(userInfo => userInfo.id)(
- action.payload.userInfos,
- );
- const userStoreOps: $ReadOnlyArray<UserStoreOperation> = [
- ...convertUserInfosToReplaceUserOps(newUserInfos),
- ...generateOpsForUserUpdates(action.payload),
- ];
-
- const processedUserInfos: UserInfos = processUserStoreOps(
- state.userInfos,
- userStoreOps,
- );
-
- if (!_isEqual(state.userInfos)(processedUserInfos)) {
- return [
- {
- ...state,
- userInfos: processedUserInfos,
- },
- [],
- userStoreOps,
- ];
+ const { payload } = action;
+ if (payload.type === stateSyncPayloadTypes.INCREMENTAL) {
+ return handleUserInfoUpdates(state, payload);
}
} else if (
action.type === processServerRequestsActionType &&
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
@@ -120,6 +120,7 @@
StateSyncFullActionPayload,
StateSyncIncrementalActionPayload,
SetActiveSessionRecoveryPayload,
+ ClientStateSyncSocketResult,
} from './socket-types.js';
import { type ClientStore } from './store-ops-types.js';
import type { SubscriptionUpdateResult } from './subscription-types.js';
@@ -1488,6 +1489,22 @@
+error: true,
+payload: Error,
+loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'FETCH_PENDING_UPDATES_STARTED',
+ +loadingInfo?: LoadingInfo,
+ +payload?: void,
+ }
+ | {
+ +type: 'FETCH_PENDING_UPDATES_SUCCESS',
+ +payload: ClientStateSyncSocketResult,
+ +loadingInfo: LoadingInfo,
+ }
+ | {
+ +type: 'FETCH_PENDING_UPDATES_FAILED',
+ +error: true,
+ +payload: Error,
+ +loadingInfo: LoadingInfo,
},
}>;
diff --git a/lib/types/session-types.js b/lib/types/session-types.js
--- a/lib/types/session-types.js
+++ b/lib/types/session-types.js
@@ -115,3 +115,8 @@
cookie: ?string,
sessionID: ?string,
}>;
+
+export type FetchPendingUpdatesInput = $ReadOnly<{
+ ...SessionState,
+ +keyserverID: string,
+}>;
diff --git a/lib/types/socket-types.js b/lib/types/socket-types.js
--- a/lib/types/socket-types.js
+++ b/lib/types/socket-types.js
@@ -300,6 +300,18 @@
serverStateSyncIncrementalSocketPayloadValidator,
]);
+export type ClientStateSyncFullSocketResult = $ReadOnly<{
+ ...ClientStateSyncFullSocketPayload,
+ +keyserverID: string,
+}>;
+export type ClientStateSyncIncrementalSocketResult = $ReadOnly<{
+ ...ClientStateSyncIncrementalSocketPayload,
+ +keyserverID: string,
+}>;
+export type ClientStateSyncSocketResult =
+ | ClientStateSyncFullSocketResult
+ | ClientStateSyncIncrementalSocketResult;
+
export type ServerStateSyncServerSocketMessage = {
+type: 0,
+responseTo: number,

File Metadata

Mime Type
text/plain
Expires
Thu, Dec 19, 10:40 PM (20 h, 49 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2679080
Default Alt Text
D12366.diff (33 KB)

Event Timeline