diff --git a/lib/types/sqlite-types.js b/lib/types/sqlite-types.js index 03d8fb89d..ad57f6a66 100644 --- a/lib/types/sqlite-types.js +++ b/lib/types/sqlite-types.js @@ -1,18 +1,25 @@ // @flow +import type { StoreOperations } from './store-ops-types.js'; + export type ReceivedMessageToDevice = { +messageID: string, +senderDeviceID: string, +plaintext: string, +status: string, }; export type SQLiteAPI = { // read operations +getAllReceivedMessageToDevice: () => Promise, // write operations +removeReceivedMessagesToDevice: ( ids: $ReadOnlyArray, ) => Promise, + + +processDBStoreOperations: ( + operations: StoreOperations, + userID?: ?string, + ) => Promise, }; diff --git a/lib/utils/__mocks__/config.js b/lib/utils/__mocks__/config.js index 833a52fbb..ec6929575 100644 --- a/lib/utils/__mocks__/config.js +++ b/lib/utils/__mocks__/config.js @@ -1,37 +1,38 @@ // @flow import { type Config } from '../config.js'; const getConfig = (): Config => ({ resolveKeyserverSessionInvalidationUsingNativeCredentials: null, setSessionIDOnRequest: true, calendarRangeInactivityLimit: null, platformDetails: { platform: 'web', codeVersion: 70, stateVersion: 50, }, authoritativeKeyserverID: '123', olmAPI: { initializeCryptoAccount: jest.fn(), getUserPublicKey: jest.fn(), encrypt: jest.fn(), decrypt: jest.fn(), decryptSequentialAndPersist: jest.fn(), contentInboundSessionCreator: jest.fn(), contentOutboundSessionCreator: jest.fn(), notificationsSessionCreator: jest.fn(), getOneTimeKeys: jest.fn(), validateAndUploadPrekeys: jest.fn(), signMessage: jest.fn(), verifyMessage: jest.fn(), }, sqliteAPI: { getAllReceivedMessageToDevice: jest.fn(), removeReceivedMessagesToDevice: jest.fn(), + processDBStoreOperations: jest.fn(), }, }); const hasConfig = (): boolean => true; export { getConfig, hasConfig }; diff --git a/native/database/sqlite-api.js b/native/database/sqlite-api.js index ac17dcc44..4b0011a05 100644 --- a/native/database/sqlite-api.js +++ b/native/database/sqlite-api.js @@ -1,15 +1,18 @@ // @flow import type { SQLiteAPI } from 'lib/types/sqlite-types.js'; import { commCoreModule } from '../native-modules.js'; +import { processDBStoreOperations } from '../redux/redux-utils.js'; const sqliteAPI: SQLiteAPI = { // read operations getAllReceivedMessageToDevice: commCoreModule.getAllReceivedMessageToDevice, // write operations removeReceivedMessagesToDevice: commCoreModule.removeReceivedMessagesToDevice, + + processDBStoreOperations, }; export { sqliteAPI }; diff --git a/web/database/sqlite-api.js b/web/database/sqlite-api.js index 731106c5f..6bd3f9568 100644 --- a/web/database/sqlite-api.js +++ b/web/database/sqlite-api.js @@ -1,36 +1,39 @@ // @flow import type { SQLiteAPI, ReceivedMessageToDevice, } from 'lib/types/sqlite-types.js'; import { getCommSharedWorker } from '../shared-worker/shared-worker-provider.js'; +import { processDBStoreOperations } from '../shared-worker/utils/store.js'; import { workerRequestMessageTypes } from '../types/worker-types.js'; const sqliteAPI: SQLiteAPI = { // read operations async getAllReceivedMessageToDevice(): Promise { const sharedWorker = await getCommSharedWorker(); const data = await sharedWorker.schedule({ type: workerRequestMessageTypes.GET_RECEIVED_MESSAGES_TO_DEVICE, }); const messages: ?$ReadOnlyArray = data?.messages; return messages ? [...messages] : []; }, // write operations async removeReceivedMessagesToDevice( ids: $ReadOnlyArray, ): Promise { const sharedWorker = await getCommSharedWorker(); await sharedWorker.schedule({ type: workerRequestMessageTypes.REMOVE_RECEIVED_MESSAGES_TO_DEVICE, ids, }); }, + + processDBStoreOperations, }; export { sqliteAPI }; diff --git a/web/shared-worker/utils/store.js b/web/shared-worker/utils/store.js index 919135958..50cd3abf7 100644 --- a/web/shared-worker/utils/store.js +++ b/web/shared-worker/utils/store.js @@ -1,244 +1,244 @@ // @flow import { auxUserStoreOpsHandlers } from 'lib/ops/aux-user-store-ops.js'; import { communityStoreOpsHandlers } from 'lib/ops/community-store-ops.js'; import { integrityStoreOpsHandlers } from 'lib/ops/integrity-store-ops.js'; import { keyserverStoreOpsHandlers } from 'lib/ops/keyserver-store-ops.js'; import { messageStoreOpsHandlers } from 'lib/ops/message-store-ops.js'; import { reportStoreOpsHandlers } from 'lib/ops/report-store-ops.js'; import { syncedMetadataStoreOpsHandlers } from 'lib/ops/synced-metadata-store-ops.js'; import { threadActivityStoreOpsHandlers } from 'lib/ops/thread-activity-store-ops.js'; import { threadStoreOpsHandlers } from 'lib/ops/thread-store-ops.js'; import { userStoreOpsHandlers } from 'lib/ops/user-store-ops.js'; import { canUseDatabaseOnWeb } from 'lib/shared/web-database.js'; import type { ClientStore, StoreOperations, } from 'lib/types/store-ops-types.js'; import { entries } from 'lib/utils/objects.js'; import { defaultWebState } from '../../redux/default-state.js'; import { workerRequestMessageTypes } from '../../types/worker-types.js'; import { getCommSharedWorker } from '../shared-worker-provider.js'; async function getClientDBStore(): Promise { const sharedWorker = await getCommSharedWorker(); let result: ClientStore = { currentUserID: null, drafts: [], messages: null, threadStore: null, messageStoreThreads: null, reports: null, users: null, keyserverInfos: defaultWebState.keyserverStore.keyserverInfos, communityInfos: null, threadHashes: null, syncedMetadata: null, auxUserInfos: null, threadActivityStore: null, }; const data = await sharedWorker.schedule({ type: workerRequestMessageTypes.GET_CLIENT_STORE, }); if (data?.store?.drafts) { result = { ...result, drafts: data.store.drafts, }; } if (data?.store?.reports) { result = { ...result, reports: reportStoreOpsHandlers.translateClientDBData(data.store.reports), }; } if (data?.store?.threads && data.store.threads.length > 0) { result = { ...result, threadStore: { threadInfos: threadStoreOpsHandlers.translateClientDBData( data.store.threads, ), }, }; } if (data?.store?.keyservers?.length) { result = { ...result, keyserverInfos: keyserverStoreOpsHandlers.translateClientDBData( data.store.keyservers, ), }; } if (data?.store?.communities) { result = { ...result, communityInfos: communityStoreOpsHandlers.translateClientDBData( data.store.communities, ), }; } if (data?.store?.integrityThreadHashes) { result = { ...result, threadHashes: integrityStoreOpsHandlers.translateClientDBData( data.store.integrityThreadHashes, ), }; } if (data?.store?.syncedMetadata) { result = { ...result, syncedMetadata: syncedMetadataStoreOpsHandlers.translateClientDBData( data.store.syncedMetadata, ), }; } if (data?.store?.auxUserInfos) { result = { ...result, auxUserInfos: auxUserStoreOpsHandlers.translateClientDBData( data.store.auxUserInfos, ), }; } if (data?.store?.users && data.store.users.length > 0) { result = { ...result, users: userStoreOpsHandlers.translateClientDBData(data.store.users), }; } if (data?.store?.messages && data.store.messages.length > 0) { result = { ...result, messages: data.store.messages, }; } if ( data?.store?.messageStoreThreads && data.store.messageStoreThreads.length > 0 ) { result = { ...result, messageStoreThreads: data.store.messageStoreThreads, }; } if ( data?.store?.threadActivityEntries && data.store.threadActivityEntries.length > 0 ) { result = { ...result, threadActivityStore: threadActivityStoreOpsHandlers.translateClientDBData( data.store.threadActivityEntries, ), }; } return result; } async function processDBStoreOperations( storeOperations: StoreOperations, - userID: null | string, + userID?: ?string, ): Promise { const { draftStoreOperations, threadStoreOperations, reportStoreOperations, keyserverStoreOperations, communityStoreOperations, integrityStoreOperations, syncedMetadataStoreOperations, auxUserStoreOperations, userStoreOperations, messageStoreOperations, threadActivityStoreOperations, } = storeOperations; const canUseDatabase = canUseDatabaseOnWeb(userID); const convertedThreadStoreOperations = canUseDatabase ? threadStoreOpsHandlers.convertOpsToClientDBOps(threadStoreOperations) : []; const convertedReportStoreOperations = reportStoreOpsHandlers.convertOpsToClientDBOps(reportStoreOperations); const convertedKeyserverStoreOperations = keyserverStoreOpsHandlers.convertOpsToClientDBOps(keyserverStoreOperations); const convertedCommunityStoreOperations = communityStoreOpsHandlers.convertOpsToClientDBOps(communityStoreOperations); const convertedIntegrityStoreOperations = integrityStoreOpsHandlers.convertOpsToClientDBOps(integrityStoreOperations); const convertedSyncedMetadataStoreOperations = syncedMetadataStoreOpsHandlers.convertOpsToClientDBOps( syncedMetadataStoreOperations, ); const convertedAuxUserStoreOperations = auxUserStoreOpsHandlers.convertOpsToClientDBOps(auxUserStoreOperations); const convertedUserStoreOperations = userStoreOpsHandlers.convertOpsToClientDBOps(userStoreOperations); const convertedMessageStoreOperations = messageStoreOpsHandlers.convertOpsToClientDBOps(messageStoreOperations); const convertedThreadActivityStoreOperations = threadActivityStoreOpsHandlers.convertOpsToClientDBOps( threadActivityStoreOperations, ); if ( convertedThreadStoreOperations.length === 0 && convertedReportStoreOperations.length === 0 && draftStoreOperations.length === 0 && convertedKeyserverStoreOperations.length === 0 && convertedCommunityStoreOperations.length === 0 && convertedIntegrityStoreOperations.length === 0 && convertedSyncedMetadataStoreOperations.length === 0 && convertedAuxUserStoreOperations.length === 0 && convertedUserStoreOperations.length === 0 && convertedMessageStoreOperations.length === 0 && convertedThreadActivityStoreOperations.length === 0 ) { return; } const sharedWorker = await getCommSharedWorker(); const isSupported = await sharedWorker.isSupported(); if (!isSupported) { return; } try { await sharedWorker.schedule({ type: workerRequestMessageTypes.PROCESS_STORE_OPERATIONS, storeOperations: { draftStoreOperations, reportStoreOperations: convertedReportStoreOperations, threadStoreOperations: convertedThreadStoreOperations, keyserverStoreOperations: convertedKeyserverStoreOperations, communityStoreOperations: convertedCommunityStoreOperations, integrityStoreOperations: convertedIntegrityStoreOperations, syncedMetadataStoreOperations: convertedSyncedMetadataStoreOperations, auxUserStoreOperations: convertedAuxUserStoreOperations, userStoreOperations: convertedUserStoreOperations, messageStoreOperations: convertedMessageStoreOperations, threadActivityStoreOperations: convertedThreadActivityStoreOperations, }, }); } catch (e) { console.log(e); if (canUseDatabase) { window.alert(e.message); if ( entries(storeOperations).some( ([key, ops]) => key !== 'draftStoreOperations' && key !== 'reportStoreOperations' && ops.length > 0, ) ) { await sharedWorker.init({ clearDatabase: true, markAsCorrupted: true }); location.reload(); } } } } export { getClientDBStore, processDBStoreOperations };