Page MenuHomePhabricator

D9328.id31854.diff
No OneTemporary

D9328.id31854.diff

diff --git a/lib/selectors/socket-selectors.js b/lib/selectors/socket-selectors.js
--- a/lib/selectors/socket-selectors.js
+++ b/lib/selectors/socket-selectors.js
@@ -7,13 +7,11 @@
currentAsOfSelector,
} from './keyserver-selectors.js';
import { currentCalendarQuery } from './nav-selectors.js';
+import type { BoundStateSyncSpec } from '../shared/state-sync/state-sync-spec.js';
import { stateSyncSpecs } from '../shared/state-sync/state-sync-specs.js';
import threadWatcher from '../shared/thread-watcher.js';
import type { SignedIdentityKeysBlob } from '../types/crypto-types.js';
-import {
- type RawEntryInfos,
- type CalendarQuery,
-} from '../types/entry-types.js';
+import { type CalendarQuery } from '../types/entry-types.js';
import type { AppState } from '../types/redux-types.js';
import type { ClientReportCreationRequest } from '../types/report-types.js';
import {
@@ -23,11 +21,9 @@
} from '../types/request-types.js';
import type { SessionState } from '../types/session-types.js';
import type { OneTimeKeyGenerator } from '../types/socket-types.js';
-import { type RawThreadInfos } from '../types/thread-types.js';
-import { type CurrentUserInfo, type UserInfos } from '../types/user-types.js';
import { getConfig } from '../utils/config.js';
import { minimumOneTimeKeysRequired } from '../utils/crypto-utils.js';
-import { hash, values } from '../utils/objects.js';
+import { values } from '../utils/objects.js';
const queuedReports: (
state: AppState,
@@ -38,6 +34,36 @@
): $ReadOnlyArray<ClientReportCreationRequest> => mainQueuedReports,
);
+// We pass all selectors specified in stateSyncSpecs and get the resulting
+// BoundStateSyncSpecs in the specs array. We do it so we don't have to
+// modify the selector when we add a new spec.
+const stateSyncSpecSelectors = values(stateSyncSpecs).map(
+ spec => spec.selector,
+);
+const boundStateSyncSpecsSelector: AppState => {
+ specsPerHashKey: { +[string]: BoundStateSyncSpec<mixed, mixed, mixed> },
+ specPerInnerHashKey: { +[string]: BoundStateSyncSpec<mixed, mixed, mixed> },
+} =
+ // The FlowFixMe is needed because createSelector types require flow
+ // to know the number of subselectors at compile time.
+ // $FlowFixMe
+ createSelector(stateSyncSpecSelectors, (...specs) => {
+ const boundSpecs = (specs: BoundStateSyncSpec<mixed, mixed, mixed>[]);
+ // We create a map from `hashKey` to a given spec for easier lookup later
+ const specsPerHashKey = Object.fromEntries(
+ boundSpecs.map(spec => [spec.hashKey, spec]),
+ );
+
+ // We do the same for innerHashKey
+ const specPerInnerHashKey = Object.fromEntries(
+ boundSpecs
+ .filter(spec => spec.innerHashSpec?.hashKey)
+ .map(spec => [spec.innerHashSpec?.hashKey, spec]),
+ );
+
+ return { specsPerHashKey, specPerInnerHashKey };
+ });
+
const getClientResponsesSelector: (
state: AppState,
) => (
@@ -47,16 +73,10 @@
getInitialNotificationsEncryptedMessage: ?() => Promise<string>,
serverRequests: $ReadOnlyArray<ClientServerRequest>,
) => Promise<$ReadOnlyArray<ClientClientResponse>> = createSelector(
- (state: AppState) => state.threadStore.threadInfos,
- (state: AppState) => state.entryStore.entryInfos,
- (state: AppState) => state.userStore.userInfos,
- (state: AppState) => state.currentUserInfo,
+ boundStateSyncSpecsSelector,
currentCalendarQuery,
(
- threadInfos: RawThreadInfos,
- entryInfos: RawEntryInfos,
- userInfos: UserInfos,
- currentUserInfo: ?CurrentUserInfo,
+ { specsPerHashKey, specPerInnerHashKey },
calendarQuery: (calendarActive: boolean) => CalendarQuery,
) => {
return async (
@@ -87,47 +107,26 @@
} else if (serverRequest.type === serverRequestTypes.CHECK_STATE) {
const query = calendarQuery(calendarActive);
- const convertedInfos = {
- [stateSyncSpecs.entries.hashKey]:
- stateSyncSpecs.entries.convertClientToServerInfos(
- entryInfos,
- query,
- ),
- [stateSyncSpecs.threads.hashKey]:
- stateSyncSpecs.threads.convertClientToServerInfos(
- threadInfos,
- query,
- ),
- [stateSyncSpecs.users.hashKey]:
- stateSyncSpecs.users.convertClientToServerInfos(userInfos, query),
- [stateSyncSpecs.currentUser.hashKey]: currentUserInfo
- ? stateSyncSpecs.currentUser.convertClientToServerInfos(
- currentUserInfo,
- query,
- )
- : currentUserInfo,
- };
-
- const specPerInnerHashKey = Object.fromEntries(
- values(stateSyncSpecs)
- .filter(spec => spec.innerHashSpec?.hashKey)
- .map(spec => [spec.innerHashSpec?.hashKey, spec]),
- );
const hashResults = {};
for (const key in serverRequest.hashesToCheck) {
const expectedHashValue = serverRequest.hashesToCheck[key];
let hashValue;
- if (convertedInfos[key]) {
- hashValue = hash(convertedInfos[key]);
+ const [specKey, id] = key.split('|');
+ if (id) {
+ hashValue = specPerInnerHashKey[specKey]?.getInfoHash(id);
} else {
- const [keyPrefix, id] = key.split('|');
- const innerSpec = specPerInnerHashKey[keyPrefix];
- if (!innerSpec || !id) {
- continue;
- }
- hashValue = hash(convertedInfos[innerSpec.hashKey][id]);
+ hashValue = specsPerHashKey[specKey]?.getAllInfosHash(query);
+ }
+
+ // If hashValue values is null then we are still calculating
+ // the hashes in the background. In this case we return true
+ // to skip this state check. Future state checks (after the hash
+ // calculation complete) will be handled normally.
+ if (!hashValue) {
+ hashResults[key] = true;
+ } else {
+ hashResults[key] = expectedHashValue === hashValue;
}
- hashResults[key] = expectedHashValue === hashValue;
}
const { failUnmentioned } = serverRequest;
@@ -136,7 +135,13 @@
if (!failUnmentioned?.[spec.hashKey] || !innerHashKey) {
continue;
}
- for (const id in convertedInfos[spec.hashKey]) {
+
+ const ids = spec.getIDs(query);
+ if (!ids) {
+ continue;
+ }
+
+ for (const id of ids) {
const key = `${innerHashKey}|${id}`;
const hashResult = hashResults[key];
if (hashResult === null || hashResult === undefined) {

File Metadata

Mime Type
text/plain
Expires
Tue, Nov 26, 11:30 AM (22 h, 2 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
2584159
Default Alt Text
D9328.id31854.diff (6 KB)

Event Timeline