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 @@ -24,6 +24,10 @@ return serverEntryInfosObject(entriesResult.rawEntryInfos); }, hashKey: 'entryInfos', - innerHashKey: 'entryInfo', + innerHashSpec: { + hashKey: 'entryInfo', + deleteKey: 'deleteEntryIDs', + rawInfosKey: 'rawEntryInfos', + }, }, ); 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 @@ -4,12 +4,17 @@ import type { Viewer } from '../../session/viewer.js'; -export type StateSyncSpec = { +export type StateSyncSpec = { +fetch: ( viewer: Viewer, calendarQuery: $ReadOnlyArray, ids?: $ReadOnlySet, ) => Promise, +hashKey: string, - +innerHashKey?: string, + +innerHashSpec?: { + +hashKey: string, + +deleteKey: string, + +rawInfosKey: string, + +additionalDeleteCondition?: Info => boolean, + }, }; 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 @@ -21,5 +21,9 @@ return result.threadInfos; }, hashKey: 'threadInfos', - innerHashKey: 'threadInfo', + innerHashSpec: { + hashKey: 'threadInfo', + deleteKey: 'deleteThreadIDs', + rawInfosKey: 'rawThreadInfos', + }, }); 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,24 +1,32 @@ // @flow import type { CalendarQuery } from 'lib/types/entry-types.js'; -import type { UserInfos } from 'lib/types/user-types.js'; +import type { UserInfos, UserInfo } from 'lib/types/user-types.js'; import type { StateSyncSpec } from './state-sync-spec.js'; import { fetchKnownUserInfos } from '../../fetchers/user-fetchers.js'; import type { Viewer } from '../../session/viewer.js'; -export const usersStateSyncSpec: StateSyncSpec = Object.freeze({ - fetch( - viewer: Viewer, - query: $ReadOnlyArray, - ids?: $ReadOnlySet, - ) { - if (ids) { - return fetchKnownUserInfos(viewer, [...ids]); - } +export const usersStateSyncSpec: StateSyncSpec = + Object.freeze({ + fetch( + viewer: Viewer, + query: $ReadOnlyArray, + ids?: $ReadOnlySet, + ) { + if (ids) { + return fetchKnownUserInfos(viewer, [...ids]); + } - return fetchKnownUserInfos(viewer); - }, - hashKey: 'userInfos', - innerHashKey: 'userInfo', -}); + return fetchKnownUserInfos(viewer); + }, + hashKey: 'userInfos', + innerHashSpec: { + hashKey: 'userInfo', + deleteKey: 'deleteUserInfoIDs', + rawInfosKey: 'userInfos', + additionalDeleteCondition(user: UserInfo) { + return !user.username; + }, + }, + }); diff --git a/keyserver/src/socket/session-utils.js b/keyserver/src/socket/session-utils.js --- a/keyserver/src/socket/session-utils.js +++ b/keyserver/src/socket/session-utils.js @@ -411,8 +411,8 @@ ); const idsToFetch = Object.fromEntries( values(serverStateSyncSpecs) - .filter(spec => spec.innerHashKey) - .map(spec => [spec.innerHashKey, new Set()]), + .filter(spec => spec.innerHashSpec?.hashKey) + .map(spec => [spec.innerHashSpec?.hashKey, new Set()]), ); for (const key of invalidKeys) { const [innerHashKey, id] = key.split('|'); @@ -425,11 +425,11 @@ for (const spec of values(serverStateSyncSpecs)) { if (shouldFetchAll[spec.hashKey]) { fetchPromises[spec.hashKey] = spec.fetch(viewer, query); - } else if (idsToFetch[spec.innerHashKey]?.size > 0) { + } else if (idsToFetch[spec.innerHashSpec?.hashKey]?.size > 0) { fetchPromises[spec.hashKey] = spec.fetch( viewer, query, - idsToFetch[spec.innerHashKey], + idsToFetch[spec.innerHashSpec?.hashKey], ); } } @@ -438,12 +438,17 @@ const specPerHashKey = Object.fromEntries( values(serverStateSyncSpecs).map(spec => [spec.hashKey, spec]), ); + const specPerInnerHashKey = Object.fromEntries( + values(serverStateSyncSpecs) + .filter(spec => spec.innerHashSpec?.hashKey) + .map(spec => [spec.innerHashSpec?.hashKey, spec]), + ); const hashesToCheck = {}, failUnmentioned = {}, stateChanges = {}; for (const key of invalidKeys) { const spec = specPerHashKey[key]; - const innerHashKey = spec?.innerHashKey; + const innerHashKey = spec?.innerHashSpec?.hashKey; const isTopLevelKey = !!spec; if (isTopLevelKey && innerHashKey) { // Instead of returning all the infos, we want to narrow down and figure @@ -455,55 +460,26 @@ failUnmentioned[key] = true; } else if (isTopLevelKey) { stateChanges[key] = fetchedData[key]; - } else if (key.startsWith('threadInfo|')) { - const [, threadID] = key.split('|'); - const threadInfos = fetchedData[serverStateSyncSpecs.threads.hashKey]; - const threadInfo = threadInfos[threadID]; - if (!threadInfo) { - if (!stateChanges.deleteThreadIDs) { - stateChanges.deleteThreadIDs = []; - } - stateChanges.deleteThreadIDs.push(threadID); + } else { + const [keyPrefix, id] = key.split('|'); + const innerSpec = specPerInnerHashKey[keyPrefix]; + const innerHashSpec = innerSpec?.innerHashSpec; + if (!innerHashSpec || !id) { continue; } - if (!stateChanges.rawThreadInfos) { - stateChanges.rawThreadInfos = []; - } - stateChanges.rawThreadInfos.push(threadInfo); - } else if (key.startsWith('entryInfo|')) { - const [, entryID] = key.split('|'); - const entryInfos = fetchedData[serverStateSyncSpecs.entries.hashKey]; - const entryInfo = entryInfos[entryID]; - if (!entryInfo) { - if (!stateChanges.deleteEntryIDs) { - stateChanges.deleteEntryIDs = []; + const infos = fetchedData[innerSpec.hashKey]; + const info = infos[id]; + if (!info || innerHashSpec.additionalDeleteCondition?.(info)) { + if (!stateChanges[innerHashSpec.deleteKey]) { + stateChanges[innerHashSpec.deleteKey] = []; } - stateChanges.deleteEntryIDs.push(entryID); + stateChanges[innerHashSpec.deleteKey].push(id); continue; } - if (!stateChanges.rawEntryInfos) { - stateChanges.rawEntryInfos = []; - } - stateChanges.rawEntryInfos.push(entryInfo); - } else if (key.startsWith('userInfo|')) { - const [, userID] = key.split('|'); - const userInfos = fetchedData[serverStateSyncSpecs.users.hashKey]; - const userInfo = userInfos[userID]; - if (!userInfo || !userInfo.username) { - if (!stateChanges.deleteUserInfoIDs) { - stateChanges.deleteUserInfoIDs = []; - } - stateChanges.deleteUserInfoIDs.push(userID); - } else { - if (!stateChanges.userInfos) { - stateChanges.userInfos = []; - } - stateChanges.userInfos.push({ - ...userInfo, - // Flow gets confused if we don't do this - username: userInfo.username, - }); + if (!stateChanges[innerHashSpec.rawInfosKey]) { + stateChanges[innerHashSpec.rawInfosKey] = []; } + stateChanges[innerHashSpec.rawInfosKey].push(info); } }