Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F3492228
D12366.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
33 KB
Referenced Files
None
Subscribers
None
D12366.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D12366: [lib] Introduce fetchPendingUpdates action
Attached
Detach File
Event Timeline
Log In to Comment