diff --git a/keyserver/src/creators/message-report-creator.js b/keyserver/src/creators/message-report-creator.js --- a/keyserver/src/creators/message-report-creator.js +++ b/keyserver/src/creators/message-report-creator.js @@ -75,26 +75,24 @@ viewer, request.messageID, ); - const promises = {}; - - promises.viewerUsername = fetchUsername(viewer.id); + const viewerUsernamePromise = fetchUsername(viewer.id); const keyserverAdminID = await keyserverAdminIDPromise; if (!keyserverAdminID) { throw new ServerError('keyserver_admin_not_found'); } - promises.commbotThreadID = getCommbotThreadID(keyserverAdminID); + const commbotThreadIDPromise = getCommbotThreadID(keyserverAdminID); const reportedMessage = await reportedMessagePromise; - if (reportedMessage) { - promises.reportedThread = serverThreadInfoFromMessageInfo(reportedMessage); - } + const reportedThreadPromise: Promise = reportedMessage + ? serverThreadInfoFromMessageInfo(reportedMessage) + : Promise.resolve(undefined); const reportedMessageAuthorID = reportedMessage?.creatorID; - if (reportedMessageAuthorID) { - promises.reportedMessageAuthor = fetchUsername(reportedMessageAuthorID); - } + const reportedMessageAuthorPromise: Promise = reportedMessageAuthorID + ? fetchUsername(reportedMessageAuthorID) + : Promise.resolve(undefined); const reportedMessageText = reportedMessage?.type === 0 ? reportedMessage.text : null; @@ -104,7 +102,12 @@ commbotThreadID, reportedThread, reportedMessageAuthor, - } = await promiseAll(promises); + } = await promiseAll({ + viewerUsername: viewerUsernamePromise, + commbotThreadID: commbotThreadIDPromise, + reportedThread: reportedThreadPromise, + reportedMessageAuthor: reportedMessageAuthorPromise, + }); return { reportedMessageText, diff --git a/keyserver/src/creators/thread-creator.js b/keyserver/src/creators/thread-creator.js --- a/keyserver/src/creators/thread-creator.js +++ b/keyserver/src/creators/thread-creator.js @@ -185,18 +185,19 @@ return { initialMemberIDs, ghostMemberIDs }; })(); - const checkPromises = {}; - checkPromises.confirmParentPermission = confirmParentPermissionPromise; - checkPromises.threadAncestry = determineThreadAncestryPromise; - checkPromises.validateMembers = validateMembersPromise; - if (sourceMessageID) { - checkPromises.sourceMessage = fetchMessageInfoByID(viewer, sourceMessageID); - } + const sourceMessagePromise: Promise = sourceMessageID + ? fetchMessageInfoByID(viewer, sourceMessageID) + : Promise.resolve(undefined); const { sourceMessage, threadAncestry, validateMembers: { initialMemberIDs, ghostMemberIDs }, - } = await promiseAll(checkPromises); + } = await promiseAll({ + sourceMessage: sourceMessagePromise, + threadAncestry: determineThreadAncestryPromise, + validateMembers: validateMembersPromise, + confirmParentPermission: confirmParentPermissionPromise, + }); if (sourceMessage && isInvalidSidebarSource(sourceMessage)) { throw new ServerError('invalid_parameters'); diff --git a/keyserver/src/creators/update-creator.js b/keyserver/src/creators/update-creator.js --- a/keyserver/src/creators/update-creator.js +++ b/keyserver/src/creators/update-creator.js @@ -16,11 +16,14 @@ import { type CalendarQuery, defaultCalendarQuery, + type RawEntryInfos, type RawEntryInfo, + type FetchEntryInfosBase, } from 'lib/types/entry-types.js'; import { defaultNumberPerThread, type MessageSelectionCriteria, + type FetchMessageInfosResult, type RawMessageInfo, } from 'lib/types/message-types.js'; import { @@ -35,7 +38,7 @@ type RawUpdateInfo, type CreateUpdatesResult, } from 'lib/types/update-types.js'; -import type { UserInfos } from 'lib/types/user-types.js'; +import type { UserInfos, LoggedInUserInfo } from 'lib/types/user-types.js'; import { promiseAll } from 'lib/utils/promises.js'; import createIDs from './id-creator.js'; @@ -47,7 +50,10 @@ fetchEntryInfosByID, } from '../fetchers/entry-fetchers.js'; import { fetchMessageInfos } from '../fetchers/message-fetchers.js'; -import { fetchThreadInfos } from '../fetchers/thread-fetchers.js'; +import { + fetchThreadInfos, + type FetchThreadInfosResult, +} from '../fetchers/thread-fetchers.js'; import { fetchKnownUserInfos, fetchCurrentUserInfo, @@ -337,39 +343,50 @@ deleteSQLConditions.push(mergeAndConditions(sqlConditions)); } - const promises = {}; - - if (insertRows.length > 0) { + const insertPromise = (async () => { + if (insertRows.length === 0) { + return; + } const insertQuery = SQL` INSERT INTO updates(id, user, type, \`key\`, content, time, updater, target) `; insertQuery.append(SQL`VALUES ${insertRows}`); - promises.insert = dbQuery(insertQuery); - } + await dbQuery(insertQuery); + })(); - if (publishInfos.size > 0) { - promises.redis = redisPublish(publishInfos.values(), dontBroadcastSession); - } + const redisPromise = + publishInfos.size > 0 + ? redisPublish(publishInfos.values(), dontBroadcastSession) + : Promise.resolve(undefined); - if (deleteSQLConditions.length > 0) { - promises.delete = (async () => { - while (deleteSQLConditions.length > 0) { - const batch = deleteSQLConditions.splice(0, deleteUpdatesBatchSize); - await deleteUpdatesByConditions(batch); - } - })(); - } + const deletePromise = (async () => { + if (deleteSQLConditions.length === 0) { + return; + } + while (deleteSQLConditions.length > 0) { + const batch = deleteSQLConditions.splice(0, deleteUpdatesBatchSize); + await deleteUpdatesByConditions(batch); + } + })(); - if (viewerRawUpdateInfos.length > 0) { + const updatesPromise: Promise = (async () => { + if (viewerRawUpdateInfos.length === 0) { + return undefined; + } invariant(viewerInfo, 'should be set'); - promises.updatesResult = fetchUpdateInfosWithRawUpdateInfos( + return await fetchUpdateInfosWithRawUpdateInfos( viewerRawUpdateInfos, viewerInfo, ); - } + })(); - const { updatesResult } = await promiseAll(promises); + const { updatesResult } = await promiseAll({ + updatesResult: updatesPromise, + insertResult: insertPromise, + redisResult: redisPromise, + deleteResult: deletePromise, + }); if (!updatesResult) { return defaultUpdateCreationResult; } @@ -407,27 +424,31 @@ entitiesToFetch.map(({ userID }) => userID).filter(Boolean), ); - const promises = {}; - const { viewer } = viewerInfo; - if (!viewerInfo.threadInfos && threadIDsNeedingFetch.size > 0) { - promises.threadResult = fetchThreadInfos(viewer, { + const threadPromise: Promise = (async () => { + if (viewerInfo.threadInfos || threadIDsNeedingFetch.size === 0) { + return undefined; + } + return await fetchThreadInfos(viewer, { threadIDs: threadIDsNeedingFetch, }); - } + })(); - let calendarQuery: ?CalendarQuery = viewerInfo.calendarQuery - ? viewerInfo.calendarQuery - : null; - if (!calendarQuery && viewer.hasSessionInfo) { + let calendarQueryTmp: ?CalendarQuery = viewerInfo.calendarQuery ?? null; + if (!calendarQueryTmp && viewer.hasSessionInfo) { // This should only ever happen for "legacy" clients who call in without // providing this information. These clients wouldn't know how to deal with // the corresponding UpdateInfos anyways, so no reason to be worried. - calendarQuery = viewer.calendarQuery; - } else if (!calendarQuery) { - calendarQuery = defaultCalendarQuery(viewer.platform, viewer.timeZone); + calendarQueryTmp = viewer.calendarQuery; + } else if (!calendarQueryTmp) { + calendarQueryTmp = defaultCalendarQuery(viewer.platform, viewer.timeZone); } - if (threadIDsNeedingDetailedFetch.size > 0) { + const calendarQuery = calendarQueryTmp; + + const messageInfosPromise: Promise = (async () => { + if (threadIDsNeedingDetailedFetch.size === 0) { + return undefined; + } const threadCursors: { [string]: ?string } = {}; for (const threadID of threadIDsNeedingDetailedFetch) { threadCursors[threadID] = null; @@ -435,11 +456,17 @@ const messageSelectionCriteria: MessageSelectionCriteria = { threadCursors, }; - promises.messageInfosResult = fetchMessageInfos( + return await fetchMessageInfos( viewer, messageSelectionCriteria, defaultNumberPerThread, ); + })(); + + const calendarPromise: Promise = (async () => { + if (threadIDsNeedingDetailedFetch.size === 0) { + return undefined; + } const threadCalendarQuery = { ...calendarQuery, filters: [ @@ -447,27 +474,31 @@ { type: 'threads', threadIDs: [...threadIDsNeedingDetailedFetch] }, ], }; - promises.calendarResult = fetchEntryInfos(viewer, [threadCalendarQuery]); - } + return await fetchEntryInfos(viewer, [threadCalendarQuery]); + })(); - if (entryIDsNeedingFetch.size > 0) { - promises.entryInfosResult = fetchEntryInfosByID( - viewer, - entryIDsNeedingFetch, - ); - } - - if (currentUserNeedsFetch) { - promises.currentUserInfoResult = (async () => { - const currentUserInfo = await fetchCurrentUserInfo(viewer); - invariant(currentUserInfo.anonymous === undefined, 'should be logged in'); - return currentUserInfo; - })(); - } + const entryInfosPromise: Promise = (async () => { + if (entryIDsNeedingFetch.size === 0) { + return undefined; + } + return await fetchEntryInfosByID(viewer, entryIDsNeedingFetch); + })(); - if (userIDsToFetch.size > 0) { - promises.userInfosResult = fetchKnownUserInfos(viewer, [...userIDsToFetch]); - } + const currentUserInfoPromise: Promise = (async () => { + if (!currentUserNeedsFetch) { + return undefined; + } + const currentUserInfo = await fetchCurrentUserInfo(viewer); + invariant(currentUserInfo.anonymous === undefined, 'should be logged in'); + return currentUserInfo; + })(); + + const userInfosPromise: Promise = (async () => { + if (userIDsToFetch.size === 0) { + return undefined; + } + return await fetchKnownUserInfos(viewer, [...userIDsToFetch]); + })(); const { threadResult, @@ -476,7 +507,14 @@ entryInfosResult, currentUserInfoResult, userInfosResult, - } = await promiseAll(promises); + } = await promiseAll({ + threadResult: threadPromise, + messageInfosResult: messageInfosPromise, + calendarResult: calendarPromise, + entryInfosResult: entryInfosPromise, + currentUserInfoResult: currentUserInfoPromise, + userInfosResult: userInfosPromise, + }); let threadInfos = {}; if (viewerInfo.threadInfos) { diff --git a/keyserver/src/deleters/account-deleters.js b/keyserver/src/deleters/account-deleters.js --- a/keyserver/src/deleters/account-deleters.js +++ b/keyserver/src/deleters/account-deleters.js @@ -19,7 +19,7 @@ import { rescindPushNotifs } from '../push/rescind.js'; import { handleAsyncPromise } from '../responders/handlers.js'; import { createNewAnonymousCookie } from '../session/cookies.js'; -import type { Viewer } from '../session/viewer.js'; +import type { Viewer, AnonymousViewerData } from '../session/viewer.js'; import { fetchOlmAccount } from '../updaters/olm-account-updater.js'; async function deleteAccount(viewer: Viewer): Promise { @@ -72,16 +72,23 @@ COMMIT; `; - const promises = {}; - promises.deletion = dbQuery(deletionQuery, { multipleStatements: true }); - if (!viewer.isScriptViewer) { - promises.anonymousViewerData = createNewAnonymousCookie({ - platformDetails: viewer.platformDetails, - deviceToken: viewer.deviceToken, - }); - } - promises.username = fetchUsername(deletedUserID); - const { anonymousViewerData, username } = await promiseAll(promises); + const deletionPromise = dbQuery(deletionQuery, { multipleStatements: true }); + const anonymousViewerDataPromise: Promise = + (async () => { + if (viewer.isScriptViewer) { + return undefined; + } + return await createNewAnonymousCookie({ + platformDetails: viewer.platformDetails, + deviceToken: viewer.deviceToken, + }); + })(); + const usernamePromise = fetchUsername(deletedUserID); + const { anonymousViewerData, username } = await promiseAll({ + anonymousViewerData: anonymousViewerDataPromise, + username: usernamePromise, + deletion: deletionPromise, + }); if (username) { const issuedAt = new Date().toISOString(); const reservedUsernameMessage: ReservedUsernameMessage = { diff --git a/keyserver/src/fetchers/thread-fetchers.js b/keyserver/src/fetchers/thread-fetchers.js --- a/keyserver/src/fetchers/thread-fetchers.js +++ b/keyserver/src/fetchers/thread-fetchers.js @@ -245,7 +245,7 @@ return { threadInfos }; } -type FetchThreadInfosResult = { +export type FetchThreadInfosResult = { +threadInfos: RawThreadInfos, }; diff --git a/keyserver/src/push/rescind.js b/keyserver/src/push/rescind.js --- a/keyserver/src/push/rescind.js +++ b/keyserver/src/push/rescind.js @@ -192,18 +192,28 @@ } const numRescinds = Object.keys(deliveryPromises).length; - const promises = [promiseAll(deliveryPromises)]; - if (numRescinds > 0) { - promises.push(createIDs('notifications', numRescinds)); - } - if (rescindedIDs.length > 0) { + const dbIDsPromise: Promise> = (async () => { + if (numRescinds === 0) { + return undefined; + } + return await createIDs('notifications', numRescinds); + })(); + const rescindPromise: Promise = (async () => { + if (rescindedIDs.length === 0) { + return undefined; + } const rescindQuery = SQL` UPDATE notifications SET rescinded = 1 WHERE id IN (${rescindedIDs}) `; - promises.push(dbQuery(rescindQuery)); - } + return await dbQuery(rescindQuery); + })(); + + const [deliveryResults, dbIDs] = await Promise.all([ + promiseAll(deliveryPromises), + dbIDsPromise, + rescindPromise, + ]); - const [deliveryResults, dbIDs] = await Promise.all(promises); const newNotifRows = []; if (numRescinds > 0) { invariant(dbIDs, 'dbIDs should be set'); diff --git a/keyserver/src/push/send.js b/keyserver/src/push/send.js --- a/keyserver/src/push/send.js +++ b/keyserver/src/push/send.js @@ -8,6 +8,7 @@ import _groupBy from 'lodash/fp/groupBy.js'; import _mapValues from 'lodash/fp/mapValues.js'; import _pickBy from 'lodash/fp/pickBy.js'; +import type { QueryResults } from 'mysql'; import t from 'tcomb'; import uuidv4 from 'uuid/v4.js'; @@ -46,7 +47,6 @@ import { type GlobalUserInfo } from 'lib/types/user-types.js'; import { isDev } from 'lib/utils/dev-utils.js'; import { values } from 'lib/utils/objects.js'; -import { promiseAll } from 'lib/utils/promises.js'; import { tID, tPlatformDetails, tShape } from 'lib/utils/validation-utils.js'; import { @@ -696,10 +696,13 @@ } } - const promises = {}; // These threadInfos won't have currentUser set - promises.threadResult = fetchServerThreadInfos({ threadIDs }); - if (threadWithChangedNamesToMessages.size > 0) { + const threadPromise = fetchServerThreadInfos({ threadIDs }); + + const oldNamesPromise: Promise = (async () => { + if (threadWithChangedNamesToMessages.size === 0) { + return undefined; + } const typesThatAffectName = [ messageTypes.CHANGE_SETTINGS, messageTypes.CREATE_THREAD, @@ -728,10 +731,13 @@ ) x LEFT JOIN messages m ON m.id = x.id `); - promises.oldNames = dbQuery(oldNameQuery); - } + return await dbQuery(oldNameQuery); + })(); - const { threadResult, oldNames } = await promiseAll(promises); + const [threadResult, oldNames] = await Promise.all([ + threadPromise, + oldNamesPromise, + ]); const serverThreadInfos = threadResult.threadInfos; if (oldNames) { const [result] = oldNames; diff --git a/keyserver/src/responders/redux-state-responders.js b/keyserver/src/responders/redux-state-responders.js --- a/keyserver/src/responders/redux-state-responders.js +++ b/keyserver/src/responders/redux-state-responders.js @@ -23,6 +23,7 @@ import { defaultNumberPerThread, messageStoreValidator, + type MessageStore, } from 'lib/types/message-types.js'; import { threadPermissions } from 'lib/types/thread-permission-types.js'; import { threadTypes } from 'lib/types/thread-types-enum.js'; @@ -153,7 +154,7 @@ ]); return { threadInfos: hasNotAcknowledgedPolicies ? {} : threadInfos }; })(); - const messageStorePromise = (async () => { + const messageStorePromise: Promise = (async () => { const [ { threadInfos }, { rawMessageInfos, truncationStatuses }, @@ -287,7 +288,7 @@ return hasNotAcknowledgedPolicies ? 0 : initialTime; })(); - const pushApiPublicKeyPromise = (async () => { + const pushApiPublicKeyPromise: Promise = (async () => { const pushConfig = await getWebPushConfig(); if (!pushConfig) { if (process.env.NODE_ENV !== 'development') { diff --git a/keyserver/src/responders/user-responders.js b/keyserver/src/responders/user-responders.js --- a/keyserver/src/responders/user-responders.js +++ b/keyserver/src/responders/user-responders.js @@ -43,6 +43,7 @@ import { type CalendarQuery, rawEntryInfoValidator, + type FetchEntryInfosBase, } from 'lib/types/entry-types.js'; import { defaultNumberPerThread, @@ -73,7 +74,6 @@ } from 'lib/utils/crypto-utils.js'; import { ServerError } from 'lib/utils/errors.js'; import { values } from 'lib/utils/objects.js'; -import { promiseAll } from 'lib/utils/promises.js'; import { getPublicKeyFromSIWEStatement, isValidSIWEMessage, @@ -362,6 +362,13 @@ } const messageSelectionCriteria = { threadCursors, joinedThreads: true }; + const entriesPromise: Promise = (async () => { + if (!calendarQuery) { + return undefined; + } + return await fetchEntryInfos(viewer, [calendarQuery]); + })(); + const [ threadsResult, messagesResult, @@ -371,7 +378,7 @@ ] = await Promise.all([ fetchThreadInfos(viewer), fetchMessageInfos(viewer, messageSelectionCriteria, defaultNumberPerThread), - calendarQuery ? fetchEntryInfos(viewer, [calendarQuery]) : undefined, + entriesPromise, fetchKnownUserInfos(viewer), fetchLoggedInUserInfo(viewer), olmSessionPromise, @@ -455,11 +462,12 @@ const calendarQuery = request.calendarQuery ? normalizeCalendarQuery(request.calendarQuery) : null; - const promises = {}; - if (calendarQuery) { - promises.verifyCalendarQueryThreadIDs = - verifyCalendarQueryThreadIDs(calendarQuery); - } + const verifyCalendarQueryThreadIDsPromise = (async () => { + if (calendarQuery) { + await verifyCalendarQueryThreadIDs(calendarQuery); + } + })(); + const username = request.username ?? request.usernameOrEmail; if (!username) { if (hasMinCodeVersion(viewer.platformDetails, { native: 150 })) { @@ -473,10 +481,11 @@ FROM users WHERE LCASE(username) = LCASE(${username}) `; - promises.userQuery = dbQuery(userQuery); - const { - userQuery: [userResult], - } = await promiseAll(promises); + const userQueryPromise = dbQuery(userQuery); + const [[userResult]] = await Promise.all([ + userQueryPromise, + verifyCalendarQueryThreadIDsPromise, + ]); if (userResult.length === 0) { if (hasMinCodeVersion(viewer.platformDetails, { native: 150 })) { diff --git a/keyserver/src/session/cookies.js b/keyserver/src/session/cookies.js --- a/keyserver/src/session/cookies.js +++ b/keyserver/src/session/cookies.js @@ -29,7 +29,6 @@ import type { UserInfo } from 'lib/types/user-types.js'; import { isDev } from 'lib/utils/dev-utils.js'; import { values } from 'lib/utils/objects.js'; -import { promiseAll } from 'lib/utils/promises.js'; import { isBcryptHash, @@ -478,26 +477,34 @@ return result.viewer; } - const promises = {}; - if (result.cookieSource === cookieSources.BODY) { - // We initialize a socket's Viewer after the WebSocket handshake, since to - // properly initialize the Viewer we need a bunch of data, but that data - // can't be sent until after the handshake. Consequently, by the time we - // know that a cookie may be invalid, we are no longer communicating via - // HTTP, and have no way to set a new cookie for HEADER (web) clients. - const platformDetails = - result.type === 'invalidated' ? result.platformDetails : null; - const deviceToken = - result.type === 'invalidated' ? result.deviceToken : null; - promises.anonymousViewerData = createNewAnonymousCookie({ - platformDetails, - deviceToken, - }); - } - if (result.type === 'invalidated') { - promises.deleteCookie = deleteCookie(result.cookieID); - } - const { anonymousViewerData } = await promiseAll(promises); + const anonymousViewerDataPromise: Promise = + (async () => { + if (result.cookieSource !== cookieSources.BODY) { + return undefined; + } + // We initialize a socket's Viewer after the WebSocket handshake, since to + // properly initialize the Viewer we need a bunch of data, but that data + // can't be sent until after the handshake. Consequently, by the time we + // know that a cookie may be invalid, we are no longer communicating via + // HTTP, and have no way to set a new cookie for HEADER (web) clients. + const platformDetails = + result.type === 'invalidated' ? result.platformDetails : null; + const deviceToken = + result.type === 'invalidated' ? result.deviceToken : null; + return await createNewAnonymousCookie({ + platformDetails, + deviceToken, + }); + })(); + const deleteCookiePromise = (async () => { + if (result.type === 'invalidated') { + await deleteCookie(result.cookieID); + } + })(); + const [anonymousViewerData] = await Promise.all([ + anonymousViewerDataPromise, + deleteCookiePromise, + ]); if (!anonymousViewerData) { return null; @@ -520,9 +527,15 @@ } const deviceToken = result.type === 'invalidated' ? result.deviceToken : null; + const deleteCookiePromise = (async () => { + if (result.type === 'invalidated') { + await deleteCookie(result.cookieID); + } + })(); + const [anonymousViewerData] = await Promise.all([ createNewAnonymousCookie({ platformDetails, deviceToken }), - result.type === 'invalidated' ? deleteCookie(result.cookieID) : null, + deleteCookiePromise, ]); return createViewerForInvalidFetchViewerResult(result, anonymousViewerData); diff --git a/keyserver/src/socket/socket.js b/keyserver/src/socket/socket.js --- a/keyserver/src/socket/socket.js +++ b/keyserver/src/socket/socket.js @@ -81,7 +81,7 @@ isCookieMissingSignedIdentityKeysBlob, isCookieMissingOlmNotificationsSession, } from '../session/cookies.js'; -import { Viewer } from '../session/viewer.js'; +import { Viewer, type AnonymousViewerData } from '../session/viewer.js'; import { serverStateSyncSpecs } from '../shared/state-sync/state-sync-specs.js'; import { commitSessionUpdate } from '../updaters/session-updaters.js'; import { compressMessage } from '../utils/compress.js'; @@ -313,15 +313,21 @@ } else if (error.message === 'client_version_unsupported') { const { viewer } = this; invariant(viewer, 'should be set'); - const promises = {}; - promises.deleteCookie = deleteCookie(viewer.cookieID); - if (viewer.cookieSource !== cookieSources.BODY) { - promises.anonymousViewerData = createNewAnonymousCookie({ - platformDetails: error.platformDetails, - deviceToken: viewer.deviceToken, - }); - } - const { anonymousViewerData } = await promiseAll(promises); + const deleteCookiePromise = deleteCookie(viewer.cookieID); + const anonymousViewerDataPromise: Promise = + (async () => { + if (viewer.cookieSource === cookieSources.BODY) { + return undefined; + } + return await createNewAnonymousCookie({ + platformDetails: error.platformDetails, + deviceToken: viewer.deviceToken, + }); + })(); + const [anonymousViewerData] = await Promise.all([ + anonymousViewerDataPromise, + deleteCookiePromise, + ]); let authErrorMessage: AuthErrorServerSocketMessage = { type: serverSocketMessageTypes.AUTH_ERROR, responseTo, @@ -441,7 +447,7 @@ async handleClientSocketMessage( message: ClientSocketMessage, ): Promise { - const resultPromise = (async () => { + const resultPromise: Promise = (async () => { if (message.type === clientSocketMessageTypes.INITIAL) { this.markActivityOccurred(); return await this.handleInitialClientSocketMessage(message); @@ -459,7 +465,7 @@ } return []; })(); - const timeoutPromise = (async () => { + const timeoutPromise: Promise = (async () => { await sleep(serverResponseTimeout); throw new ServerError('socket_response_timeout'); })(); @@ -568,18 +574,19 @@ const { sessionUpdate, deltaEntryInfoResult } = sessionInitializationResult; - const promises = {}; - promises.deleteExpiredUpdates = deleteUpdatesBeforeTimeTargetingSession( - viewer, - oldUpdatesCurrentAsOf, - ); - promises.fetchUpdateResult = fetchUpdateInfos( + const deleteExpiredUpdatesPromise = + deleteUpdatesBeforeTimeTargetingSession(viewer, oldUpdatesCurrentAsOf); + const fetchUpdateResultPromise = fetchUpdateInfos( viewer, oldUpdatesCurrentAsOf, calendarQuery, ); - promises.sessionUpdate = commitSessionUpdate(viewer, sessionUpdate); - const { fetchUpdateResult } = await promiseAll(promises); + const sessionUpdatePromise = commitSessionUpdate(viewer, sessionUpdate); + const [fetchUpdateResult] = await Promise.all([ + fetchUpdateResultPromise, + deleteExpiredUpdatesPromise, + sessionUpdatePromise, + ]); const { updateInfos, userInfos } = fetchUpdateResult; const newUpdatesCurrentAsOf = mostRecentUpdateTimestamp( diff --git a/keyserver/src/updaters/thread-permission-updaters.js b/keyserver/src/updaters/thread-permission-updaters.js --- a/keyserver/src/updaters/thread-permission-updaters.js +++ b/keyserver/src/updaters/thread-permission-updaters.js @@ -121,6 +121,19 @@ INNER JOIN memberships cm ON cm.thread = t.containing_thread_id WHERE t.id = ${threadID} AND cm.user IN (${userIDs}) `; + const containingMembershipPromise: Promise< + $ReadOnlyArray<{ + +user: number, + +containing_role: number, + }>, + > = (async () => { + if (intent === 'leave') { + // Membership in the container only needs to be checked for members + return []; + } + const [result] = await dbQuery(containingMembershipQuery); + return result; + })(); const [ [membershipResults], [parentMembershipResults], @@ -129,14 +142,7 @@ ] = await Promise.all([ dbQuery(membershipQuery), dbQuery(parentMembershipQuery), - (async () => { - if (intent === 'leave') { - // Membership in the container only needs to be checked for members - return []; - } - const [result] = await dbQuery(containingMembershipQuery); - return result; - })(), + containingMembershipPromise, changeRoleThreadQuery(threadID, role), ]); diff --git a/keyserver/src/updaters/thread-updaters.js b/keyserver/src/updaters/thread-updaters.js --- a/keyserver/src/updaters/thread-updaters.js +++ b/keyserver/src/updaters/thread-updaters.js @@ -39,6 +39,7 @@ changeRole, recalculateThreadPermissions, commitMembershipChangeset, + type MembershipChangeset, type MembershipRow, } from './thread-permission-updaters.js'; import createMessages from '../creators/message-creator.js'; @@ -341,7 +342,6 @@ const silenceMessages = options?.silenceMessages ?? false; const ignorePermissions = (options?.ignorePermissions && viewer.isScriptViewer) ?? false; - const validationPromises = {}; const changedFields: { [string]: string | number } = {}; const sqlUpdate: { [string]: ?string | number } = {}; @@ -352,12 +352,12 @@ throw new ServerError('invalid_chat_name'); } changedFields.name = name; - sqlUpdate.name = name ?? null; + sqlUpdate.name = name; } const { description } = request.changes; if (description !== undefined && description !== null) { changedFields.description = description; - sqlUpdate.description = description ?? null; + sqlUpdate.description; } if (request.changes.color) { const color = request.changes.color.toLowerCase(); @@ -406,11 +406,11 @@ throw new ServerError('invalid_parameters'); } - validationPromises.serverThreadInfos = fetchServerThreadInfos({ + const serverThreadInfosPromise = fetchServerThreadInfos({ threadID: request.threadID, }); - validationPromises.hasNecessaryPermissions = (async () => { + const hasNecessaryPermissionsPromise = (async () => { if (ignorePermissions) { return; } @@ -461,7 +461,10 @@ } })(); - const { serverThreadInfos } = await promiseAll(validationPromises); + const [serverThreadInfos] = await Promise.all([ + serverThreadInfosPromise, + hasNecessaryPermissionsPromise, + ]); const serverThreadInfo = serverThreadInfos.threadInfos[request.threadID]; if (!serverThreadInfo) { @@ -701,30 +704,35 @@ } })(); - const intermediatePromises = {}; - intermediatePromises.updateQuery = updateQueryPromise; - intermediatePromises.updateRoles = updateRolesPromise; - - if (newMemberIDs) { - intermediatePromises.addMembersChangeset = (async () => { + const addMembersChangesetPromise: Promise = + (async () => { + if (!newMemberIDs) { + return undefined; + } await Promise.all([updateQueryPromise, updateRolesPromise]); return await changeRole(request.threadID, newMemberIDs, null, { setNewMembersToUnread: true, }); })(); - } - const threadRootChanged = - rolesNeedUpdate || nextParentThreadID !== oldParentThreadID; - if (threadRootChanged) { - intermediatePromises.recalculatePermissionsChangeset = (async () => { + const recalculatePermissionsChangesetPromise: Promise = + (async () => { + const threadRootChanged = + rolesNeedUpdate || nextParentThreadID !== oldParentThreadID; + if (!threadRootChanged) { + return undefined; + } await Promise.all([updateQueryPromise, updateRolesPromise]); return await recalculateThreadPermissions(request.threadID); })(); - } - const { addMembersChangeset, recalculatePermissionsChangeset } = - await promiseAll(intermediatePromises); + const [addMembersChangeset, recalculatePermissionsChangeset] = + await Promise.all([ + addMembersChangesetPromise, + recalculatePermissionsChangesetPromise, + updateQueryPromise, + updateRolesPromise, + ]); const membershipRows: Array = []; const relationshipChangeset = new RelationshipChangeset();