Parallelize SQL queries

This commit is contained in:
Fedor Indutny 2024-07-22 11:16:33 -07:00 committed by GitHub
parent 86b4da1ec2
commit c64762858e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
178 changed files with 3377 additions and 3618 deletions

View file

@ -2513,18 +2513,6 @@ Signal Desktop makes use of the following open source projects.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## p-props
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
## p-queue
MIT License

View file

@ -68,11 +68,11 @@ async function cleanupOrphanedAttachments({
}: CleanupOrphanedAttachmentsOptionsType): Promise<void> {
await deleteAllBadges({
userDataPath,
pathsToKeep: await sql.sqlCall('getAllBadgeImageFileLocalPaths'),
pathsToKeep: await sql.sqlRead('getAllBadgeImageFileLocalPaths'),
});
const allStickers = await getAllStickers(userDataPath);
const orphanedStickers = await sql.sqlCall(
const orphanedStickers = await sql.sqlWrite(
'removeKnownStickers',
allStickers
);
@ -82,7 +82,7 @@ async function cleanupOrphanedAttachments({
});
const allDraftAttachments = await getAllDraftAttachments(userDataPath);
const orphanedDraftAttachments = await sql.sqlCall(
const orphanedDraftAttachments = await sql.sqlWrite(
'removeKnownDraftAttachments',
allDraftAttachments
);
@ -100,7 +100,7 @@ async function cleanupOrphanedAttachments({
);
{
const attachments: ReadonlyArray<string> = await sql.sqlCall(
const attachments: ReadonlyArray<string> = await sql.sqlRead(
'getKnownConversationAttachments'
);
@ -142,7 +142,7 @@ function deleteOrphanedAttachments({
let attachments: ReadonlyArray<string>;
// eslint-disable-next-line no-await-in-loop
({ attachments, cursor } = await sql.sqlCall(
({ attachments, cursor } = await sql.sqlRead(
'getKnownMessageAttachments',
cursor
));
@ -166,7 +166,7 @@ function deleteOrphanedAttachments({
} while (cursor !== undefined && !cursor.done);
} finally {
if (cursor !== undefined) {
await sql.sqlCall('finishGetKnownMessageAttachments', cursor);
await sql.sqlRead('finishGetKnownMessageAttachments', cursor);
}
}

View file

@ -396,14 +396,14 @@ async function getLocaleOverrideSetting(): Promise<string | null> {
const zoomFactorService = new ZoomFactorService({
async getZoomFactorSetting() {
const item = await sql.sqlCall('getItemById', 'zoomFactor');
const item = await sql.sqlRead('getItemById', 'zoomFactor');
if (typeof item?.value !== 'number') {
return null;
}
return item.value;
},
async setZoomFactorSetting(zoomFactor) {
await sql.sqlCall('createOrUpdateItem', {
await sql.sqlWrite('createOrUpdateItem', {
id: 'zoomFactor',
value: zoomFactor,
});
@ -1433,8 +1433,8 @@ async function showSettingsWindow() {
async function getIsLinked() {
try {
const number = await sql.sqlCall('getItemById', 'number_id');
const password = await sql.sqlCall('getItemById', 'password');
const number = await sql.sqlRead('getItemById', 'number_id');
const password = await sql.sqlRead('getItemById', 'password');
return Boolean(number && password);
} catch (e) {
return false;
@ -1686,7 +1686,7 @@ async function initializeSQL(
try {
// This should be the first awaited call in this function, otherwise
// `sql.sqlCall` will throw an uninitialized error instead of waiting for
// `sql.sqlRead` will throw an uninitialized error instead of waiting for
// init to finish.
await sql.initialize({
appVersion: app.getVersion(),
@ -2154,10 +2154,10 @@ app.on('ready', async () => {
try {
const IDB_KEY = 'indexeddb-delete-needed';
const item = await sql.sqlCall('getItemById', IDB_KEY);
const item = await sql.sqlRead('getItemById', IDB_KEY);
if (item && item.value) {
await sql.sqlCall('removeIndexedDBFiles');
await sql.sqlCall('removeItemById', IDB_KEY);
await sql.sqlWrite('removeIndexedDBFiles');
await sql.sqlWrite('removeItemById', IDB_KEY);
}
} catch (err) {
getLogger().error(

View file

@ -7,14 +7,22 @@ import type { MainSQL } from '../ts/sql/main';
import { remove as removeUserConfig } from './user_config';
import { remove as removeEphemeralConfig } from './ephemeral_config';
let sql: Pick<MainSQL, 'sqlCall'> | undefined;
let sql:
| Pick<
MainSQL,
'sqlRead' | 'sqlWrite' | 'pauseWriteAccess' | 'resumeWriteAccess'
>
| undefined;
let initialized = false;
const SQL_CHANNEL_KEY = 'sql-channel';
const SQL_READ_KEY = 'sql-channel:read';
const SQL_WRITE_KEY = 'sql-channel:write';
const ERASE_SQL_KEY = 'erase-sql-key';
const PAUSE_WRITE_ACCESS = 'pause-sql-writes';
const RESUME_WRITE_ACCESS = 'resume-sql-writes';
export function initialize(mainSQL: Pick<MainSQL, 'sqlCall'>): void {
export function initialize(mainSQL: typeof sql): void {
if (initialized) {
throw new Error('sqlChannels: already initialized!');
}
@ -22,15 +30,36 @@ export function initialize(mainSQL: Pick<MainSQL, 'sqlCall'>): void {
sql = mainSQL;
ipcMain.handle(SQL_CHANNEL_KEY, (_event, callName, ...args) => {
ipcMain.handle(SQL_READ_KEY, (_event, callName, ...args) => {
if (!sql) {
throw new Error(`${SQL_CHANNEL_KEY}: Not yet initialized!`);
throw new Error(`${SQL_READ_KEY}: Not yet initialized!`);
}
return sql.sqlCall(callName, ...args);
return sql.sqlRead(callName, ...args);
});
ipcMain.handle(SQL_WRITE_KEY, (_event, callName, ...args) => {
if (!sql) {
throw new Error(`${SQL_WRITE_KEY}: Not yet initialized!`);
}
return sql.sqlWrite(callName, ...args);
});
ipcMain.handle(ERASE_SQL_KEY, () => {
removeUserConfig();
removeEphemeralConfig();
});
ipcMain.handle(PAUSE_WRITE_ACCESS, () => {
if (!sql) {
throw new Error(`${PAUSE_WRITE_ACCESS}: Not yet initialized!`);
}
return sql.pauseWriteAccess();
});
ipcMain.handle(RESUME_WRITE_ACCESS, () => {
if (!sql) {
throw new Error(`${PAUSE_WRITE_ACCESS}: Not yet initialized!`);
}
return sql.resumeWriteAccess();
});
}

32
package-lock.json generated
View file

@ -70,7 +70,6 @@
"nop": "1.0.0",
"normalize-path": "3.0.0",
"p-map": "2.1.0",
"p-props": "4.0.0",
"p-queue": "6.6.2",
"p-timeout": "4.1.0",
"parchment": "1.1.4",
@ -12652,6 +12651,7 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.0.1.tgz",
"integrity": "sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA==",
"dev": true,
"dependencies": {
"clean-stack": "^2.0.0",
"indent-string": "^4.0.0"
@ -15491,6 +15491,7 @@
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz",
"integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==",
"dev": true,
"engines": {
"node": ">=6"
}
@ -22852,6 +22853,7 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz",
"integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==",
"dev": true,
"engines": {
"node": ">=8"
}
@ -28836,34 +28838,6 @@
"node": ">=6"
}
},
"node_modules/p-props": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-props/-/p-props-4.0.0.tgz",
"integrity": "sha512-3iKFbPdoPG7Ne3cMA53JnjPsTMaIzE9gxKZnvKJJivTAeqLEZPBu6zfi6DYq9AsH1nYycWmo3sWCNI8Kz6T2Zg==",
"dependencies": {
"p-map": "^4.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-props/node_modules/p-map": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz",
"integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==",
"dependencies": {
"aggregate-error": "^3.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/p-queue": {
"version": "6.6.2",
"resolved": "https://registry.npmjs.org/p-queue/-/p-queue-6.6.2.tgz",

View file

@ -152,7 +152,6 @@
"nop": "1.0.0",
"normalize-path": "3.0.0",
"p-map": "2.1.0",
"p-props": "4.0.0",
"p-queue": "6.6.2",
"p-timeout": "4.1.0",
"parchment": "1.1.4",

View file

@ -8,14 +8,6 @@
mocha.setup('bdd');
mocha.setup({ timeout: 10000 });
function deleteIndexedDB() {
return new Promise((resolve, reject) => {
const idbReq = indexedDB.deleteDatabase('test');
idbReq.onsuccess = resolve;
idbReq.error = reject;
});
}
window.Events = {
getThemeSetting: () => 'light',
};
@ -23,8 +15,6 @@ window.Events = {
/* Delete the database before running any tests */
before(async () => {
await window.testUtilities.initialize();
await deleteIndexedDB();
await window.Signal.Data.removeAll();
await window.storage.fetch();
});

View file

@ -7,7 +7,7 @@ import type { IPCResponse as ChallengeResponseType } from './challenge';
import type { MessageAttributesType } from './model-types.d';
import * as log from './logging/log';
import { explodePromise } from './util/explodePromise';
import { ipcInvoke } from './sql/channels';
import { AccessType, ipcInvoke } from './sql/channels';
import { backupsService } from './services/backups';
import { SECOND } from './util/durations';
import { isSignalRoute } from './util/signalRoutes';
@ -128,6 +128,7 @@ export function getCI({ deviceName, backupData }: GetCIOptionsType): CIType {
async function getMessagesBySentAt(sentAt: number) {
const messages = await ipcInvoke<ReadonlyArray<MessageAttributesType>>(
AccessType.Read,
'getMessagesBySentAt',
[sentAt]
);

View file

@ -6,6 +6,7 @@ import { v4 as uuid } from 'uuid';
import { incrementMessageCounter } from '../util/incrementMessageCounter';
import { ReadStatus } from '../messages/MessageReadStatus';
import { SendStatus } from '../messages/MessageSendState';
import { DataWriter } from '../sql/Client';
import { BodyRange } from '../types/BodyRange';
import { strictAssert } from '../util/assert';
import { MINUTE } from '../util/durations';
@ -86,13 +87,13 @@ export async function populateConversationWithMessages({
timestamp += 1;
}
await window.Signal.Data.saveMessages(messages, {
await DataWriter.saveMessages(messages, {
forceSave: true,
ourAci,
});
conversation.set('active_at', Date.now());
await window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
log.info(`${logId}: populating conversation complete`);
}

View file

@ -14,7 +14,7 @@ import type {
} from './model-types.d';
import type { ConversationModel } from './models/conversations';
import dataInterface from './sql/Client';
import { DataReader, DataWriter } from './sql/Client';
import * as log from './logging/log';
import * as Errors from './types/errors';
import { getAuthorId } from './messages/helpers';
@ -127,11 +127,15 @@ const {
getAllConversations,
getAllGroupsInvolvingServiceId,
getMessagesBySentAt,
} = DataReader;
const {
migrateConversationMessages,
removeConversation,
saveConversation,
updateConversation,
} = dataInterface;
updateConversations,
} = DataWriter;
// We have to run this in background.js, after all backbone models and collections on
// Whisper.* have been created. Once those are in typescript we can use more reasonable
@ -443,12 +447,12 @@ export class ConversationController {
conversation.set({
profileAvatar: { hash: SIGNAL_AVATAR_PATH, path: SIGNAL_AVATAR_PATH },
});
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
}
if (!conversation.get('profileName')) {
conversation.set({ profileName: 'Signal' });
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
}
this._signalConversationId = conversation.id;
@ -934,7 +938,7 @@ export class ConversationController {
);
existing.set({ e164: undefined });
updateConversation(existing.attributes);
drop(updateConversation(existing.attributes));
byE164[e164] = conversation;
@ -1144,7 +1148,7 @@ export class ConversationController {
group.set({
members: currentAdded,
});
updateConversation(group.attributes);
drop(updateConversation(group.attributes));
});
}
@ -1337,7 +1341,7 @@ export class ConversationController {
);
convo.set('isPinned', true);
window.Signal.Data.updateConversation(convo.attributes);
drop(updateConversation(convo.attributes));
}
}
@ -1353,7 +1357,7 @@ export class ConversationController {
`updating ${sharedWith.length} conversations`
);
await window.Signal.Data.updateConversations(
await updateConversations(
sharedWith.map(c => {
c.unset('shareMyPhoneNumber');
return c.attributes;
@ -1440,7 +1444,7 @@ export class ConversationController {
const isChanged = maybeDeriveGroupV2Id(conversation);
if (isChanged) {
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
}
// In case a too-large draft was saved to the database
@ -1449,7 +1453,7 @@ export class ConversationController {
conversation.set({
draft: draft.slice(0, MAX_MESSAGE_BODY_LENGTH),
});
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
}
// Clean up the conversations that have service id as their e164.
@ -1457,7 +1461,7 @@ export class ConversationController {
const serviceId = conversation.getServiceId();
if (e164 && isServiceIdString(e164) && serviceId) {
conversation.set({ e164: undefined });
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
log.info(
`Cleaning up conversation(${serviceId}) with invalid e164`

View file

@ -18,10 +18,13 @@ import {
SignedPreKeyRecord,
} from '@signalapp/libsignal-client';
import { DataReader, DataWriter } from './sql/Client';
import type { ItemType } from './sql/Interface';
import * as Bytes from './Bytes';
import { constantTimeEqual, sha256 } from './Crypto';
import { assertDev, strictAssert } from './util/assert';
import { isNotNil } from './util/isNotNil';
import { drop } from './util/drop';
import { Zone } from './util/Zone';
import { isMoreRecentThan } from './util/timestamp';
import {
@ -294,7 +297,9 @@ export class SignalProtocolStore extends EventEmitter {
await Promise.all([
(async () => {
this.ourIdentityKeys.clear();
const map = await window.Signal.Data.getItemById('identityKeyMap');
const map = (await DataReader.getItemById(
'identityKeyMap'
)) as unknown as ItemType<'identityKeyMap'>;
if (!map) {
return;
}
@ -313,7 +318,9 @@ export class SignalProtocolStore extends EventEmitter {
})(),
(async () => {
this.ourRegistrationIds.clear();
const map = await window.Signal.Data.getItemById('registrationIdMap');
const map = (await DataReader.getItemById(
'registrationIdMap'
)) as unknown as ItemType<'registrationIdMap'>;
if (!map) {
return;
}
@ -329,32 +336,32 @@ export class SignalProtocolStore extends EventEmitter {
_fillCaches<string, IdentityKeyType, PublicKey>(
this,
'identityKeys',
window.Signal.Data.getAllIdentityKeys()
DataReader.getAllIdentityKeys()
),
_fillCaches<string, KyberPreKeyType, KyberPreKeyRecord>(
this,
'kyberPreKeys',
window.Signal.Data.getAllKyberPreKeys()
DataReader.getAllKyberPreKeys()
),
_fillCaches<string, SessionType, SessionRecord>(
this,
'sessions',
window.Signal.Data.getAllSessions()
DataReader.getAllSessions()
),
_fillCaches<string, PreKeyType, PreKeyRecord>(
this,
'preKeys',
window.Signal.Data.getAllPreKeys()
DataReader.getAllPreKeys()
),
_fillCaches<string, SenderKeyType, SenderKeyRecord>(
this,
'senderKeys',
window.Signal.Data.getAllSenderKeys()
DataReader.getAllSenderKeys()
),
_fillCaches<string, SignedPreKeyType, SignedPreKeyRecord>(
this,
'signedPreKeys',
window.Signal.Data.getAllSignedPreKeys()
DataReader.getAllSignedPreKeys()
),
]);
}
@ -470,7 +477,7 @@ export class SignalProtocolStore extends EventEmitter {
},
};
await window.Signal.Data.createOrUpdateKyberPreKey(confirmedItem.fromDB);
await DataWriter.createOrUpdateKyberPreKey(confirmedItem.fromDB);
kyberPreKeyCache.set(id, confirmedItem);
}
@ -505,7 +512,7 @@ export class SignalProtocolStore extends EventEmitter {
toSave.push(kyberPreKey);
});
await window.Signal.Data.bulkAddKyberPreKeys(toSave);
await DataWriter.bulkAddKyberPreKeys(toSave);
toSave.forEach(kyberPreKey => {
kyberPreKeyCache.set(kyberPreKey.id, {
hydrated: false,
@ -546,7 +553,7 @@ export class SignalProtocolStore extends EventEmitter {
const ids = keyIds.map(keyId => this._getKeyId(ourServiceId, keyId));
log.info('removeKyberPreKeys: Removing kyber prekeys:', formatKeys(keyIds));
const changes = await window.Signal.Data.removeKyberPreKeyById(ids);
const changes = await DataWriter.removeKyberPreKeyById(ids);
log.info(`removeKyberPreKeys: Removed ${changes} kyber prekeys`);
ids.forEach(id => {
kyberPreKeyCache.delete(id);
@ -564,7 +571,7 @@ export class SignalProtocolStore extends EventEmitter {
if (this.kyberPreKeys) {
this.kyberPreKeys.clear();
}
const changes = await window.Signal.Data.removeAllKyberPreKeys();
const changes = await DataWriter.removeAllKyberPreKeys();
log.info(`clearKyberPreKeyStore: Removed ${changes} kyber prekeys`);
}
@ -646,7 +653,7 @@ export class SignalProtocolStore extends EventEmitter {
});
log.info(`storePreKeys: Saving ${toSave.length} prekeys`);
await window.Signal.Data.bulkAddPreKeys(toSave);
await DataWriter.bulkAddPreKeys(toSave);
toSave.forEach(preKey => {
preKeyCache.set(preKey.id, {
hydrated: false,
@ -668,7 +675,7 @@ export class SignalProtocolStore extends EventEmitter {
log.info('removePreKeys: Removing prekeys:', formatKeys(keyIds));
const changes = await window.Signal.Data.removePreKeyById(ids);
const changes = await DataWriter.removePreKeyById(ids);
log.info(`removePreKeys: Removed ${changes} prekeys`);
ids.forEach(id => {
preKeyCache.delete(id);
@ -683,7 +690,7 @@ export class SignalProtocolStore extends EventEmitter {
if (this.preKeys) {
this.preKeys.clear();
}
const changes = await window.Signal.Data.removeAllPreKeys();
const changes = await DataWriter.removeAllPreKeys();
log.info(`clearPreKeyStore: Removed ${changes} prekeys`);
}
@ -769,7 +776,7 @@ export class SignalProtocolStore extends EventEmitter {
},
};
await window.Signal.Data.createOrUpdateSignedPreKey(confirmedItem.fromDB);
await DataWriter.createOrUpdateSignedPreKey(confirmedItem.fromDB);
signedPreKeyCache.set(id, confirmedItem);
}
@ -796,7 +803,7 @@ export class SignalProtocolStore extends EventEmitter {
confirmed: Boolean(confirmed),
};
await window.Signal.Data.createOrUpdateSignedPreKey(fromDB);
await DataWriter.createOrUpdateSignedPreKey(fromDB);
this.signedPreKeys.set(id, {
hydrated: false,
fromDB,
@ -818,7 +825,7 @@ export class SignalProtocolStore extends EventEmitter {
'removeSignedPreKeys: Removing signed prekeys:',
formatKeys(keyIds)
);
await window.Signal.Data.removeSignedPreKeyById(ids);
await DataWriter.removeSignedPreKeyById(ids);
ids.forEach(id => {
signedPreKeyCache.delete(id);
});
@ -828,7 +835,7 @@ export class SignalProtocolStore extends EventEmitter {
if (this.signedPreKeys) {
this.signedPreKeys.clear();
}
const changes = await window.Signal.Data.removeAllSignedPreKeys();
const changes = await DataWriter.removeAllSignedPreKeys();
log.info(`clearSignedPreKeysStore: Removed ${changes} signed prekeys`);
}
@ -992,7 +999,7 @@ export class SignalProtocolStore extends EventEmitter {
try {
const id = this.getSenderKeyId(qualifiedAddress, distributionId);
await window.Signal.Data.removeSenderKeyById(id);
await DataWriter.removeSenderKeyById(id);
this.senderKeys.delete(id);
} catch (error) {
@ -1011,7 +1018,7 @@ export class SignalProtocolStore extends EventEmitter {
if (this.pendingSenderKeys) {
this.pendingSenderKeys.clear();
}
await window.Signal.Data.removeAllSenderKeys();
await DataWriter.removeAllSenderKeys();
});
}
@ -1191,7 +1198,7 @@ export class SignalProtocolStore extends EventEmitter {
// Commit both sender keys, sessions and unprocessed in the same database transaction
// to unroll both on error.
await window.Signal.Data.commitDecryptResult({
await DataWriter.commitDecryptResult({
senderKeys: Array.from(pendingSenderKeys.values()).map(
({ fromDB }) => fromDB
),
@ -1593,7 +1600,7 @@ export class SignalProtocolStore extends EventEmitter {
const id = qualifiedAddress.toString();
log.info('removeSession: deleting session for', id);
try {
await window.Signal.Data.removeSessionById(id);
await DataWriter.removeSessionById(id);
this.sessions.delete(id);
this.pendingSessions.delete(id);
} catch (e) {
@ -1640,7 +1647,7 @@ export class SignalProtocolStore extends EventEmitter {
}
}
await window.Signal.Data.removeSessionsByConversation(id);
await DataWriter.removeSessionsByConversation(id);
}
);
}
@ -1665,7 +1672,7 @@ export class SignalProtocolStore extends EventEmitter {
}
}
await window.Signal.Data.removeSessionsByServiceId(serviceId);
await DataWriter.removeSessionsByServiceId(serviceId);
});
}
@ -1772,7 +1779,7 @@ export class SignalProtocolStore extends EventEmitter {
this.sessions.clear();
}
this.pendingSessions.clear();
const changes = await window.Signal.Data.removeAllSessions();
const changes = await DataWriter.removeAllSessions();
log.info(`clearSessionStore: Removed ${changes} sessions`);
});
}
@ -1893,9 +1900,7 @@ export class SignalProtocolStore extends EventEmitter {
await this._saveIdentityKey(newRecord);
this.identityKeys.delete(record.fromDB.id);
const changes = await window.Signal.Data.removeIdentityKeyById(
record.fromDB.id
);
const changes = await DataWriter.removeIdentityKeyById(record.fromDB.id);
log.info(
`getOrMigrateIdentityRecord: Removed ${changes} old identity keys for ${record.fromDB.id}`
@ -2042,7 +2047,7 @@ export class SignalProtocolStore extends EventEmitter {
const { id } = data;
await window.Signal.Data.createOrUpdateIdentityKey(data);
await DataWriter.createOrUpdateIdentityKey(data);
this.identityKeys.set(id, {
hydrated: false,
fromDB: data,
@ -2345,7 +2350,7 @@ export class SignalProtocolStore extends EventEmitter {
// We only want to clear previousIdentityKey on a match, or on successfully emit.
conversation.set({ previousIdentityKey: undefined });
window.Signal.Data.updateConversation(conversation.attributes);
drop(DataWriter.updateConversation(conversation.attributes));
} catch (error) {
log.error(
'saveIdentity: error triggering keychange:',
@ -2462,20 +2467,20 @@ export class SignalProtocolStore extends EventEmitter {
const id = serviceId;
this.identityKeys.delete(id);
await window.Signal.Data.removeIdentityKeyById(serviceId);
await DataWriter.removeIdentityKeyById(serviceId);
await this.removeSessionsByServiceId(serviceId);
}
// Not yet processed messages - for resiliency
getUnprocessedCount(): Promise<number> {
return this.withZone(GLOBAL_ZONE, 'getUnprocessedCount', async () => {
return window.Signal.Data.getUnprocessedCount();
return DataReader.getUnprocessedCount();
});
}
getAllUnprocessedIds(): Promise<Array<string>> {
return this.withZone(GLOBAL_ZONE, 'getAllUnprocessedIds', () => {
return window.Signal.Data.getAllUnprocessedIds();
return DataWriter.getAllUnprocessedIds();
});
}
@ -2486,14 +2491,14 @@ export class SignalProtocolStore extends EventEmitter {
GLOBAL_ZONE,
'getAllUnprocessedByIdsAndIncrementAttempts',
async () => {
return window.Signal.Data.getUnprocessedByIdsAndIncrementAttempts(ids);
return DataWriter.getUnprocessedByIdsAndIncrementAttempts(ids);
}
);
}
getUnprocessedById(id: string): Promise<UnprocessedType | undefined> {
return this.withZone(GLOBAL_ZONE, 'getUnprocessedById', async () => {
return window.Signal.Data.getUnprocessedById(id);
return DataReader.getUnprocessedById(id);
});
}
@ -2531,7 +2536,7 @@ export class SignalProtocolStore extends EventEmitter {
data: UnprocessedUpdateType
): Promise<void> {
return this.withZone(GLOBAL_ZONE, 'updateUnprocessedWithData', async () => {
await window.Signal.Data.updateUnprocessedWithData(id, data);
await DataWriter.updateUnprocessedWithData(id, data);
});
}
@ -2542,14 +2547,14 @@ export class SignalProtocolStore extends EventEmitter {
GLOBAL_ZONE,
'updateUnprocessedsWithData',
async () => {
await window.Signal.Data.updateUnprocessedsWithData(items);
await DataWriter.updateUnprocessedsWithData(items);
}
);
}
removeUnprocessed(idOrArray: string | Array<string>): Promise<void> {
return this.withZone(GLOBAL_ZONE, 'removeUnprocessed', async () => {
await window.Signal.Data.removeUnprocessed(idOrArray);
await DataWriter.removeUnprocessed(idOrArray);
});
}
@ -2557,7 +2562,7 @@ export class SignalProtocolStore extends EventEmitter {
removeAllUnprocessed(): Promise<void> {
log.info('removeAllUnprocessed');
return this.withZone(GLOBAL_ZONE, 'removeAllUnprocessed', async () => {
await window.Signal.Data.removeAllUnprocessed();
await DataWriter.removeAllUnprocessed();
});
}
@ -2603,9 +2608,9 @@ export class SignalProtocolStore extends EventEmitter {
'registrationIdMap',
omit(storage.get('registrationIdMap') || {}, oldPni)
),
window.Signal.Data.removePreKeysByServiceId(oldPni),
window.Signal.Data.removeSignedPreKeysByServiceId(oldPni),
window.Signal.Data.removeKyberPreKeysByServiceId(oldPni),
DataWriter.removePreKeysByServiceId(oldPni),
DataWriter.removeSignedPreKeysByServiceId(oldPni),
DataWriter.removeKyberPreKeysByServiceId(oldPni),
]);
}
@ -2695,7 +2700,7 @@ export class SignalProtocolStore extends EventEmitter {
}
async removeAllData(): Promise<void> {
await window.Signal.Data.removeAll();
await DataWriter.removeAll();
await this.hydrateCaches();
window.storage.reset();
@ -2716,7 +2721,7 @@ export class SignalProtocolStore extends EventEmitter {
conversation.unset('senderKeyInfo');
});
await window.Signal.Data.removeAllConfiguration();
await DataWriter.removeAllConfiguration();
await this.hydrateCaches();

View file

@ -209,6 +209,7 @@ import { isEnabled } from './RemoteConfig';
import { AttachmentBackupManager } from './jobs/AttachmentBackupManager';
import { getConversationIdForLogging } from './util/idForLogging';
import { encryptConversationAttachments } from './util/encryptConversationAttachments';
import { DataReader, DataWriter } from './sql/Client';
export function isOverHourIntoPast(timestamp: number): boolean {
return isNumber(timestamp) && isOlderThan(timestamp, HOUR);
@ -256,7 +257,7 @@ export async function startApp(): Promise<void> {
let initialBadgesState: BadgesStateType = { byId: {} };
async function loadInitialBadgesState(): Promise<void> {
initialBadgesState = {
byId: makeLookup(await window.Signal.Data.getAllBadges(), 'id'),
byId: makeLookup(await DataReader.getAllBadges(), 'id'),
};
}
@ -436,7 +437,7 @@ export async function startApp(): Promise<void> {
window.i18n
);
const version = await window.Signal.Data.getItemById('version');
const version = await DataReader.getItemById('version');
if (!version) {
const isIndexedDBPresent = await indexedDb.doesDatabaseExist();
if (isIndexedDBPresent) {
@ -472,8 +473,8 @@ export async function startApp(): Promise<void> {
await Promise.all([
indexedDb.removeDatabase(),
window.Signal.Data.removeAll(),
window.Signal.Data.removeIndexedDBFiles(),
DataWriter.removeAll(),
DataWriter.removeIndexedDBFiles(),
]);
log.info('Done with SQL deletion and IndexedDB file deletion.');
} catch (error) {
@ -485,7 +486,7 @@ export async function startApp(): Promise<void> {
// Set a flag to delete IndexedDB on next startup if it wasn't deleted just now.
// We need to use direct data calls, since window.storage isn't ready yet.
await window.Signal.Data.createOrUpdateItem({
await DataWriter.createOrUpdateItem({
id: 'indexeddb-delete-needed',
value: true,
});
@ -826,7 +827,7 @@ export async function startApp(): Promise<void> {
log.info('background/shutdown: closing the database');
// Shut down the data interface cleanly
await window.Signal.Data.shutdown();
await DataWriter.shutdown();
},
});
@ -926,12 +927,12 @@ export async function startApp(): Promise<void> {
key: legacyChallengeKey,
});
await window.Signal.Data.clearAllErrorStickerPackAttempts();
await DataWriter.clearAllErrorStickerPackAttempts();
}
if (window.isBeforeVersion(lastVersion, 'v5.51.0-beta.2')) {
await window.storage.put('groupCredentials', []);
await window.Signal.Data.removeAllProfileKeyCredentials();
await DataWriter.removeAllProfileKeyCredentials();
}
if (window.isBeforeVersion(lastVersion, 'v6.38.0-beta.1')) {
@ -963,9 +964,9 @@ export async function startApp(): Promise<void> {
if (newVersion || window.storage.get('needOrphanedAttachmentCheck')) {
await window.storage.remove('needOrphanedAttachmentCheck');
await window.Signal.Data.cleanupOrphanedAttachments();
await DataWriter.cleanupOrphanedAttachments();
drop(window.Signal.Data.ensureFilePermissions());
drop(DataWriter.ensureFilePermissions());
}
if (
@ -1004,9 +1005,8 @@ export async function startApp(): Promise<void> {
const batchWithIndex = await migrateMessageData({
numMessagesPerBatch: NUM_MESSAGES_PER_BATCH,
upgradeMessageSchema,
getMessagesNeedingUpgrade:
window.Signal.Data.getMessagesNeedingUpgrade,
saveMessages: window.Signal.Data.saveMessages,
getMessagesNeedingUpgrade: DataReader.getMessagesNeedingUpgrade,
saveMessages: DataWriter.saveMessages,
});
log.info('idleDetector/idle: Upgraded messages:', batchWithIndex);
isMigrationWithIndexComplete = batchWithIndex.done;
@ -1056,9 +1056,7 @@ export async function startApp(): Promise<void> {
}
try {
await window.Signal.Data.deleteSentProtosOlderThan(
now - sentProtoMaxAge
);
await DataWriter.deleteSentProtosOlderThan(now - sentProtoMaxAge);
} catch (error) {
log.error(
'background/onready/setInterval: Error deleting sent protos: ',
@ -1412,7 +1410,7 @@ export async function startApp(): Promise<void> {
log.info('Expiration start timestamp cleanup: starting...');
const messagesUnexpectedlyMissingExpirationStartTimestamp =
await window.Signal.Data.getMessagesUnexpectedlyMissingExpirationStartTimestamp();
await DataReader.getMessagesUnexpectedlyMissingExpirationStartTimestamp();
log.info(
`Expiration start timestamp cleanup: Found ${messagesUnexpectedlyMissingExpirationStartTimestamp.length} messages for cleanup`
);
@ -1446,7 +1444,7 @@ export async function startApp(): Promise<void> {
};
});
await window.Signal.Data.saveMessages(newMessageAttributes, {
await DataWriter.saveMessages(newMessageAttributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
@ -1454,10 +1452,10 @@ export async function startApp(): Promise<void> {
{
log.info('Startup/syncTasks: Fetching tasks');
const syncTasks = await window.Signal.Data.getAllSyncTasks();
const syncTasks = await DataWriter.getAllSyncTasks();
log.info(`Startup/syncTasks: Queueing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, window.Signal.Data.removeSyncTaskById);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info('`Startup/syncTasks: Done');
}
@ -2402,7 +2400,7 @@ export async function startApp(): Promise<void> {
`for ${sender.idForLogging()}`
);
sender.set({ shareMyPhoneNumber: true });
window.Signal.Data.updateConversation(sender.attributes);
drop(DataWriter.updateConversation(sender.attributes));
}
if (!message.get('unidentifiedDeliveryReceived')) {
@ -2585,7 +2583,7 @@ export async function startApp(): Promise<void> {
const conversation = window.ConversationController.get(id)!;
conversation.enableProfileSharing();
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
// Then we update our own profileKey if it's different from what we have
const ourId = window.ConversationController.getOurConversationId();
@ -3037,14 +3035,14 @@ export async function startApp(): Promise<void> {
window.ConversationController.getOurConversation();
if (ourConversation) {
ourConversation.unset('username');
window.Signal.Data.updateConversation(ourConversation.attributes);
await DataWriter.updateConversation(ourConversation.attributes);
}
// Then make sure outstanding conversation saves are flushed
await window.Signal.Data.flushUpdateConversationBatcher();
await DataWriter.flushUpdateConversationBatcher();
// Then make sure that all previously-outstanding database saves are flushed
await window.Signal.Data.getItemById('manifestVersion');
await DataReader.getItemById('manifestVersion');
// Finally, conversations in the database, and delete all config tables
await window.textsecure.storage.protocol.removeAllConfiguration();
@ -3319,13 +3317,13 @@ export async function startApp(): Promise<void> {
log.info(`${logId}: Saving ${syncTasks.length} sync tasks`);
await window.Signal.Data.saveSyncTasks(syncTasks);
await DataWriter.saveSyncTasks(syncTasks);
confirm();
log.info(`${logId}: Queuing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, window.Signal.Data.removeSyncTaskById);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info(`${logId}: Done`);
}
@ -3391,13 +3389,13 @@ export async function startApp(): Promise<void> {
log.info(`${logId}: Saving ${syncTasks.length} sync tasks`);
await window.Signal.Data.saveSyncTasks(syncTasks);
await DataWriter.saveSyncTasks(syncTasks);
confirm();
log.info(`${logId}: Queuing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, window.Signal.Data.removeSyncTaskById);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info(`${logId}: Done`);
}
@ -3463,13 +3461,13 @@ export async function startApp(): Promise<void> {
log.info(`${logId}: Saving ${syncTasks.length} sync tasks`);
await window.Signal.Data.saveSyncTasks(syncTasks);
await DataWriter.saveSyncTasks(syncTasks);
confirm();
log.info(`${logId}: Queuing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, window.Signal.Data.removeSyncTaskById);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info(`${logId}: Done`);
}
@ -3544,13 +3542,13 @@ export async function startApp(): Promise<void> {
log.info(`${logId}: Saving ${syncTasks.length} sync tasks`);
await window.Signal.Data.saveSyncTasks(syncTasks);
await DataWriter.saveSyncTasks(syncTasks);
confirm();
log.info(`${logId}: Queuing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, window.Signal.Data.removeSyncTaskById);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info(`${logId}: Done`);
}
@ -3579,13 +3577,13 @@ export async function startApp(): Promise<void> {
sentAt: timestamp,
type: item.type,
}));
await window.Signal.Data.saveSyncTasks(syncTasks);
await DataWriter.saveSyncTasks(syncTasks);
confirm();
log.info(`${logId}: Queuing ${syncTasks.length} sync tasks`);
await queueSyncTasks(syncTasks, window.Signal.Data.removeSyncTaskById);
await queueSyncTasks(syncTasks, DataWriter.removeSyncTaskById);
log.info(`${logId}: Done`);
}

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import PQueue from 'p-queue';
import { DataWriter } from '../sql/Client';
import * as log from '../logging/log';
import { MINUTE } from '../util/durations';
import { missingCaseError } from '../util/missingCaseError';
@ -100,7 +101,7 @@ async function downloadBadgeImageFile(url: string): Promise<string> {
imageFileData
);
await window.Signal.Data.badgeImageFileDownloaded(url, localPath);
await DataWriter.badgeImageFileDownloaded(url, localPath);
window.reduxActions.badges.badgeImageFileDownloaded(url, localPath);

View file

@ -19,7 +19,7 @@ import {
maybeFetchNewCredentials,
} from './services/groupCredentialFetcher';
import { storageServiceUploadJob } from './services/storage';
import dataInterface from './sql/Client';
import { DataReader, DataWriter } from './sql/Client';
import { toWebSafeBase64, fromWebSafeBase64 } from './util/webSafeBase64';
import { assertDev, strictAssert } from './util/assert';
import { isMoreRecentThan } from './util/timestamp';
@ -263,7 +263,7 @@ const groupFieldsCache = new LRU<string, GroupFields>({
max: MAX_CACHED_GROUP_FIELDS,
});
const { updateConversation } = dataInterface;
const { updateConversation } = DataWriter;
if (!isNumber(MAX_MESSAGE_SCHEMA)) {
throw new Error(
@ -1602,9 +1602,7 @@ export async function modifyGroupV2({
groupMembersV2: membersV2,
});
await dataInterface.replaceAllEndorsementsForGroup(
groupEndorsementData
);
await DataWriter.replaceAllEndorsementsForGroup(groupEndorsementData);
}
});
@ -1921,7 +1919,7 @@ export async function createGroupV2(
groupMembersV2: membersV2,
});
await dataInterface.replaceAllEndorsementsForGroup(groupEndorsementData);
await DataWriter.replaceAllEndorsementsForGroup(groupEndorsementData);
} catch (error) {
if (!(error instanceof HTTPError)) {
throw error;
@ -2023,7 +2021,7 @@ export async function createGroupV2(
details: [{ type: 'create' }],
},
};
await dataInterface.saveMessages([createdTheGroupMessage], {
await DataWriter.saveMessages([createdTheGroupMessage], {
forceSave: true,
ourAci,
});
@ -2482,7 +2480,7 @@ export async function initiateMigrationToGroupV2(
}
// Save these most recent updates to conversation
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
strictAssert(
Bytes.isNotEmpty(groupSendEndorsementResponse),
@ -2496,7 +2494,7 @@ export async function initiateMigrationToGroupV2(
groupMembersV2: membersV2,
});
await dataInterface.replaceAllEndorsementsForGroup(groupEndorsementData);
await DataWriter.replaceAllEndorsementsForGroup(groupEndorsementData);
});
} catch (error) {
const logId = conversation.idForLogging();
@ -2960,7 +2958,7 @@ export async function respondToGroupV2Migration({
}
// Save these most recent updates to conversation
updateConversation(conversation.attributes);
await updateConversation(conversation.attributes);
// Finally, check for any changes to the group since its initial creation using normal
// group update codepaths.
@ -2983,7 +2981,7 @@ export async function respondToGroupV2Migration({
groupMembersV2: membersV2,
});
await dataInterface.replaceAllEndorsementsForGroup(groupEndorsementData);
await DataWriter.replaceAllEndorsementsForGroup(groupEndorsementData);
}
}
@ -3364,7 +3362,7 @@ async function appendChangeMessages(
const ourAci = window.textsecure.storage.user.getCheckedAci();
let lastMessage = await dataInterface.getLastConversationMessage({
let lastMessage = await DataReader.getLastConversationMessage({
conversationId: conversation.id,
});
@ -3400,7 +3398,7 @@ async function appendChangeMessages(
strictAssert(first !== undefined, 'First message must be there');
log.info(`appendChangeMessages/${logId}: updating ${first.id}`);
await dataInterface.saveMessage(first, {
await DataWriter.saveMessage(first, {
ourAci,
// We don't use forceSave here because this is an update of existing
@ -3410,7 +3408,7 @@ async function appendChangeMessages(
log.info(
`appendChangeMessages/${logId}: saving ${rest.length} new messages`
);
await dataInterface.saveMessages(rest, {
await DataWriter.saveMessages(rest, {
ourAci,
forceSave: true,
});
@ -3418,7 +3416,7 @@ async function appendChangeMessages(
log.info(
`appendChangeMessages/${logId}: saving ${mergedMessages.length} new messages`
);
await dataInterface.saveMessages(mergedMessages, {
await DataWriter.saveMessages(mergedMessages, {
ourAci,
forceSave: true,
});
@ -3766,7 +3764,7 @@ async function updateGroupViaState({
groupMembersV2: membersV2,
});
await dataInterface.replaceAllEndorsementsForGroup(groupEndorsementData);
await DataWriter.replaceAllEndorsementsForGroup(groupEndorsementData);
}
return {
@ -3890,7 +3888,7 @@ async function updateGroupViaLogs({
strictAssert(groupId != null, 'Group must have groupId');
let cachedEndorsementsExpiration =
await dataInterface.getGroupSendCombinedEndorsementExpiration(groupId);
await DataReader.getGroupSendCombinedEndorsementExpiration(groupId);
let response: GroupLogResponseType;
let groupSendEndorsementResponse: Uint8Array | null = null;
@ -3925,7 +3923,7 @@ async function updateGroupViaLogs({
'updateGroupViaLogs: Received paginated response, deleting group endorsements'
);
// eslint-disable-next-line no-await-in-loop
await dataInterface.deleteAllEndorsementsForGroup(groupId);
await DataWriter.deleteAllEndorsementsForGroup(groupId);
cachedEndorsementsExpiration = null; // gets sent as 0 in header
}
@ -3971,7 +3969,7 @@ async function updateGroupViaLogs({
groupSecretParamsBase64: secretParams,
});
await dataInterface.replaceAllEndorsementsForGroup(groupEndorsementData);
await DataWriter.replaceAllEndorsementsForGroup(groupEndorsementData);
}
return updates;

View file

@ -7,6 +7,7 @@ import type { ConversationAttributesType } from '../model-types.d';
import type { ConversationModel } from '../models/conversations';
import type { PreJoinConversationType } from '../state/ducks/conversations';
import { DataWriter } from '../sql/Client';
import * as Bytes from '../Bytes';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
@ -160,7 +161,7 @@ export async function joinViaLink(value: string): Promise<void> {
const active_at = existingConversation.get('active_at') || Date.now();
// eslint-disable-next-line camelcase
existingConversation.set({ active_at, timestamp });
window.Signal.Data.updateConversation(existingConversation.attributes);
await DataWriter.updateConversation(existingConversation.attributes);
// We're waiting for the left pane to re-sort before we navigate to that conversation
await sleep(200);
@ -320,7 +321,7 @@ export async function joinViaLink(value: string): Promise<void> {
temporaryMemberCount: memberCount,
timestamp,
});
window.Signal.Data.updateConversation(
await DataWriter.updateConversation(
targetConversation.attributes
);
}
@ -343,9 +344,7 @@ export async function joinViaLink(value: string): Promise<void> {
// We want to keep this conversation around, since the join succeeded
isTemporary: undefined,
});
window.Signal.Data.updateConversation(
tempConversation.attributes
);
await DataWriter.updateConversation(tempConversation.attributes);
}
window.reduxActions.conversations.showConversation({
@ -357,7 +356,7 @@ export async function joinViaLink(value: string): Promise<void> {
window.ConversationController.dangerouslyRemoveById(
tempConversation.id
);
await window.Signal.Data.removeConversation(tempConversation.id);
await DataWriter.removeConversation(tempConversation.id);
}
throw error;

View file

@ -7,7 +7,7 @@ import { PassThrough } from 'node:stream';
import * as durations from '../util/durations';
import * as log from '../logging/log';
import dataInterface from '../sql/Client';
import { DataWriter } from '../sql/Client';
import * as Errors from '../types/errors';
import { redactGenericText } from '../util/privacy';
@ -81,10 +81,10 @@ const THUMBNAIL_RETRY_CONFIG = {
export class AttachmentBackupManager extends JobManager<CoreAttachmentBackupJobType> {
private static _instance: AttachmentBackupManager | undefined;
static defaultParams: JobManagerParamsType<CoreAttachmentBackupJobType> = {
markAllJobsInactive: dataInterface.markAllAttachmentBackupJobsInactive,
saveJob: dataInterface.saveAttachmentBackupJob,
removeJob: dataInterface.removeAttachmentBackupJob,
getNextJobs: dataInterface.getNextAttachmentBackupJobs,
markAllJobsInactive: DataWriter.markAllAttachmentBackupJobsInactive,
saveJob: DataWriter.saveAttachmentBackupJob,
removeJob: DataWriter.removeAttachmentBackupJob,
getNextJobs: DataWriter.getNextAttachmentBackupJobs,
runJob: runAttachmentBackupJob,
shouldHoldOffOnStartingQueuedJobs: () => {
const reduxState = window.reduxStore?.getState();
@ -604,7 +604,7 @@ async function copyToBackupTier({
// Update our local understanding of what's in the backup cdn
const sizeOnBackupCdn = getAesCbcCiphertextLength(ciphertextLength);
await window.Signal.Data.saveBackupCdnObjectMetadata([
await DataWriter.saveBackupCdnObjectMetadata([
{ mediaId, cdnNumber: response.cdn, sizeOnBackupCdn },
]);

View file

@ -14,7 +14,7 @@ import {
AttachmentPermanentlyUndownloadableError,
downloadAttachment as downloadAttachmentUtil,
} from '../util/downloadAttachment';
import dataInterface from '../sql/Client';
import { DataWriter } from '../sql/Client';
import { getValue } from '../RemoteConfig';
import { isInCall as isInCallSelector } from '../state/selectors/calling';
@ -103,10 +103,10 @@ export class AttachmentDownloadManager extends JobManager<CoreAttachmentDownload
override logPrefix = 'AttachmentDownloadManager';
static defaultParams: AttachmentDownloadManagerParamsType = {
markAllJobsInactive: dataInterface.resetAttachmentDownloadActive,
saveJob: dataInterface.saveAttachmentDownloadJob,
removeJob: dataInterface.removeAttachmentDownloadJob,
getNextJobs: dataInterface.getNextAttachmentDownloadJobs,
markAllJobsInactive: DataWriter.resetAttachmentDownloadActive,
saveJob: DataWriter.saveAttachmentDownloadJob,
removeJob: DataWriter.removeAttachmentDownloadJob,
getNextJobs: DataWriter.getNextAttachmentDownloadJobs,
runDownloadAttachmentJob,
shouldHoldOffOnStartingQueuedJobs: () => {
const reduxState = window.reduxStore?.getState();
@ -321,7 +321,7 @@ async function runDownloadAttachmentJob({
} finally {
// This will fail if the message has been deleted before the download finished, which
// is good
await dataInterface.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -6,7 +6,7 @@ import { AsyncQueue } from '../util/AsyncQueue';
import { concat, wrapPromise } from '../util/asyncIterables';
import type { JobQueueStore, StoredJob } from './types';
import { formatJobForInsert } from './formatJobForInsert';
import databaseInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import * as log from '../logging/log';
type Database = {
@ -107,6 +107,8 @@ export class JobQueueDatabaseStore implements JobQueueStore {
}
}
export const jobQueueDatabaseStore = new JobQueueDatabaseStore(
databaseInterface
);
export const jobQueueDatabaseStore = new JobQueueDatabaseStore({
getJobsInQueue: DataReader.getJobsInQueue,
insertJob: DataWriter.insertJob,
deleteJob: DataWriter.deleteJob,
});

View file

@ -5,7 +5,7 @@ import * as z from 'zod';
import type { LoggerType } from '../types/Logging';
import { applyNewAvatar } from '../groups';
import { isGroupV2 } from '../util/whatTypeOfConversation';
import Data from '../sql/Client';
import { DataWriter } from '../sql/Client';
import type { JOB_STATUS } from './JobQueue';
import { JobQueue } from './JobQueue';
@ -46,7 +46,7 @@ export class GroupAvatarJobQueue extends JobQueue<GroupAvatarJobData> {
const patch = await applyNewAvatar(newAvatarUrl, attributes, logId);
convo.set(patch);
await Data.updateConversation(convo.attributes);
await DataWriter.updateConversation(convo.attributes);
return undefined;
}

View file

@ -17,6 +17,7 @@ import {
} from './handleMultipleSendErrors';
import { ourProfileKeyService } from '../../services/ourProfileKey';
import { wrapWithSyncMessageSend } from '../../util/wrapWithSyncMessageSend';
import { DataWriter } from '../../sql/Client';
import type { ConversationModel } from '../../models/conversations';
import type {
@ -302,7 +303,7 @@ async function updateMessageWithSuccessfulSends(
deletedForEveryoneSendStatus: {},
deletedForEveryoneFailed: undefined,
});
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -325,7 +326,7 @@ async function updateMessageWithSuccessfulSends(
deletedForEveryoneSendStatus,
deletedForEveryoneFailed: undefined,
});
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
@ -341,7 +342,7 @@ async function updateMessageWithFailure(
);
message.set({ deletedForEveryoneFailed: true });
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -10,6 +10,7 @@ import {
maybeExpandErrors,
} from './handleMultipleSendErrors';
import { ourProfileKeyService } from '../../services/ourProfileKey';
import { DataWriter } from '../../sql/Client';
import type { ConversationModel } from '../../models/conversations';
import type {
@ -277,7 +278,7 @@ async function updateMessageWithSuccessfulSends(
deletedForEveryoneSendStatus: {},
deletedForEveryoneFailed: undefined,
});
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -300,7 +301,7 @@ async function updateMessageWithSuccessfulSends(
deletedForEveryoneSendStatus,
deletedForEveryoneFailed: undefined,
});
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
@ -316,7 +317,7 @@ async function updateMessageWithFailure(
);
message.set({ deletedForEveryoneFailed: true });
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -5,6 +5,7 @@ import { isNumber } from 'lodash';
import PQueue from 'p-queue';
import { v4 as generateUuid } from 'uuid';
import { DataWriter } from '../../sql/Client';
import * as Errors from '../../types/errors';
import { strictAssert } from '../../util/assert';
import type { MessageModel } from '../../models/messages';
@ -650,7 +651,7 @@ async function getMessageSendData({
]);
// Save message after uploading attachments
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -1106,7 +1107,7 @@ async function markMessageFailed({
}): Promise<void> {
message.markFailed(targetTimestamp);
void message.saveErrors(errors, { skipSave: true });
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -11,6 +11,7 @@ import type { CallbackResultType } from '../../textsecure/Types.d';
import type { MessageModel } from '../../models/messages';
import type { MessageReactionType } from '../../model-types.d';
import type { ConversationModel } from '../../models/conversations';
import { DataWriter } from '../../sql/Client';
import * as reactionUtil from '../../reactions/util';
import { isSent, SendStatus } from '../../messages/MessageSendState';
@ -86,7 +87,7 @@ export async function sendReaction(
if (!canReact(message.attributes, ourConversationId, findAndFormatContact)) {
log.info(`could not react to ${messageId}. Removing this pending reaction`);
markReactionFailed(message, pendingReaction);
await window.Signal.Data.saveMessage(message.attributes, { ourAci });
await DataWriter.saveMessage(message.attributes, { ourAci });
return;
}
@ -95,7 +96,7 @@ export async function sendReaction(
`reacting to message ${messageId} ran out of time. Giving up on sending it`
);
markReactionFailed(message, pendingReaction);
await window.Signal.Data.saveMessage(message.attributes, { ourAci });
await DataWriter.saveMessage(message.attributes, { ourAci });
return;
}
@ -335,7 +336,7 @@ export async function sendReaction(
await reactionMessage.hydrateStoryContext(message.attributes, {
shouldSave: false,
});
await window.Signal.Data.saveMessage(reactionMessage.attributes, {
await DataWriter.saveMessage(reactionMessage.attributes, {
ourAci,
forceSave: true,
});
@ -374,7 +375,7 @@ export async function sendReaction(
toThrow: originalError || thrownError,
});
} finally {
await window.Signal.Data.saveMessage(message.attributes, { ourAci });
await DataWriter.saveMessage(message.attributes, { ourAci });
}
}

View file

@ -23,7 +23,7 @@ import type { ServiceIdString } from '../../types/ServiceId';
import type { StoryDistributionIdString } from '../../types/StoryDistributionId';
import * as Errors from '../../types/errors';
import type { StoryMessageRecipientsType } from '../../types/Stories';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { SignalService as Proto } from '../../protobuf';
import { getMessagesById } from '../../messages/getMessagesById';
import {
@ -252,7 +252,7 @@ export async function sendStory(
const distributionList = isGroupV2(conversation.attributes)
? undefined
: await dataInterface.getStoryDistributionWithMembers(receiverId);
: await DataReader.getStoryDistributionWithMembers(receiverId);
let messageSendErrors: Array<Error> = [];
@ -541,7 +541,7 @@ export async function sendStory(
}
message.set('sendStateByConversationId', newSendStateByConversationId);
return window.Signal.Data.saveMessage(message.attributes, {
return DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
})
@ -688,7 +688,7 @@ async function markMessageFailed(
): Promise<void> {
message.markFailed();
void message.saveErrors(errors, { skipSave: true });
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -3,6 +3,7 @@
import type { MessageAttributesType } from '../model-types.d';
import { getAuthorId } from '../messages/helpers';
import { DataReader } from '../sql/Client';
import * as log from '../logging/log';
import * as Errors from '../types/errors';
import { deleteForEveryone } from '../util/deleteForEveryone';
@ -72,7 +73,7 @@ export async function onDelete(del: DeleteAttributesType): Promise<void> {
targetConversation.queueJob('Deletes.onDelete', async () => {
log.info(`${logId}: Handling DOE`);
const messages = await window.Signal.Data.getMessagesBySentAt(
const messages = await DataReader.getMessagesBySentAt(
del.targetSentTimestamp
);

View file

@ -18,9 +18,9 @@ import {
getConversationFromTarget,
getMessageQueryFromTarget,
} from '../util/deleteForMe';
import dataInterface from '../sql/Client';
import { DataWriter } from '../sql/Client';
const { removeSyncTaskById } = dataInterface;
const { removeSyncTaskById } = DataWriter;
export type DeleteForMeAttributesType = {
conversation: ConversationToDelete;

View file

@ -4,6 +4,7 @@
import type { MessageAttributesType } from '../model-types.d';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
import { DataReader } from '../sql/Client';
import { drop } from '../util/drop';
import { getAuthorId } from '../messages/helpers';
import { handleEditMessage } from '../util/handleEditMessage';
@ -117,7 +118,7 @@ export async function onEdit(edit: EditAttributesType): Promise<void> {
targetConversation.queueJob('Edits.onEdit', async () => {
log.info(`${logId}: Handling edit`);
const messages = await window.Signal.Data.getMessagesBySentAt(
const messages = await DataReader.getMessagesBySentAt(
edit.targetSentTimestamp
);

View file

@ -18,8 +18,8 @@ import {
UNDELIVERED_SEND_STATUSES,
sendStateReducer,
} from '../messages/MessageSendState';
import { DataReader, DataWriter } from '../sql/Client';
import type { DeleteSentProtoRecipientOptionsType } from '../sql/Interface';
import dataInterface from '../sql/Client';
import * as log from '../logging/log';
import { getSourceServiceId } from '../messages/helpers';
import { getMessageSentTimestamp } from '../util/getMessageSentTimestamp';
@ -31,7 +31,7 @@ import {
} from '../types/Receipt';
import { drop } from '../util/drop';
const { deleteSentProtoRecipient, removeSyncTaskById } = dataInterface;
const { deleteSentProtoRecipient, removeSyncTaskById } = DataWriter;
export const messageReceiptTypeSchema = z.enum(['Delivery', 'Read', 'View']);
@ -99,11 +99,11 @@ const processReceiptBatcher = createWaitBatcher({
const messagesMatchingTimestamp =
// eslint-disable-next-line no-await-in-loop
await window.Signal.Data.getMessagesBySentAt(sentAt);
await DataReader.getMessagesBySentAt(sentAt);
if (messagesMatchingTimestamp.length === 0) {
// eslint-disable-next-line no-await-in-loop
const reaction = await window.Signal.Data.getReactionByTimestamp(
const reaction = await DataReader.getReactionByTimestamp(
window.ConversationController.getOurConversationIdOrThrow(),
sentAt
);

View file

@ -5,6 +5,7 @@ import type { AciString } from '../types/ServiceId';
import type { MessageAttributesType } from '../model-types.d';
import type { MessageModel } from '../models/messages';
import type { ReactionSource } from '../reactions/ReactionSource';
import { DataReader } from '../sql/Client';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
import { getAuthor } from '../messages/helpers';
@ -66,9 +67,7 @@ async function findMessageForReaction({
reactionSenderConversationId: string;
logId: string;
}): Promise<MessageAttributesType | undefined> {
const messages = await window.Signal.Data.getMessagesBySentAt(
targetTimestamp
);
const messages = await DataReader.getMessagesBySentAt(targetTimestamp);
const matchingMessages = messages.filter(message =>
isMessageAMatchForReaction({

View file

@ -16,9 +16,9 @@ import { notificationService } from '../services/notifications';
import { queueUpdateMessage } from '../util/messageBatcher';
import { strictAssert } from '../util/assert';
import { isAciString } from '../util/isAciString';
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
const { removeSyncTaskById } = dataInterface;
const { removeSyncTaskById } = DataWriter;
export const readSyncTaskSchema = z.object({
type: z.literal('ReadSync').readonly(),
@ -51,7 +51,7 @@ async function maybeItIsAReactionReadSync(
const { readSync } = sync;
const logId = `ReadSyncs.onSync(timestamp=${readSync.timestamp})`;
const readReaction = await window.Signal.Data.markReactionAsRead(
const readReaction = await DataWriter.markReactionAsRead(
readSync.senderAci,
Number(readSync.timestamp)
);
@ -129,9 +129,7 @@ export async function onSync(sync: ReadSyncAttributesType): Promise<void> {
const logId = `ReadSyncs.onSync(timestamp=${readSync.timestamp})`;
try {
const messages = await window.Signal.Data.getMessagesBySentAt(
readSync.timestamp
);
const messages = await DataReader.getMessagesBySentAt(readSync.timestamp);
const found = messages.find(item => {
const sender = window.ConversationController.lookupOrCreate({

View file

@ -3,6 +3,7 @@
import type { AciString } from '../types/ServiceId';
import type { MessageModel } from '../models/messages';
import { DataReader } from '../sql/Client';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
import { getMessageIdForLogging } from '../util/idForLogging';
@ -66,9 +67,7 @@ export async function onSync(
const logId = `ViewOnceOpenSyncs.onSync(timestamp=${sync.timestamp})`;
try {
const messages = await window.Signal.Data.getMessagesBySentAt(
sync.timestamp
);
const messages = await DataReader.getMessagesBySentAt(sync.timestamp);
const found = messages.find(item => {
const itemSourceAci = item.sourceServiceId;

View file

@ -18,9 +18,7 @@ import { queueAttachmentDownloads } from '../util/queueAttachmentDownloads';
import { queueUpdateMessage } from '../util/messageBatcher';
import { AttachmentDownloadUrgency } from '../jobs/AttachmentDownloadManager';
import { isAciString } from '../util/isAciString';
import dataInterface from '../sql/Client';
const { removeSyncTaskById } = dataInterface;
import { DataReader, DataWriter } from '../sql/Client';
export const viewSyncTaskSchema = z.object({
type: z.literal('ViewSync').readonly(),
@ -42,7 +40,7 @@ export type ViewSyncAttributesType = {
const viewSyncs = new Map<string, ViewSyncAttributesType>();
async function remove(sync: ViewSyncAttributesType): Promise<void> {
await removeSyncTaskById(sync.syncTaskId);
await DataWriter.removeSyncTaskById(sync.syncTaskId);
}
export async function forMessage(
@ -92,9 +90,7 @@ export async function onSync(sync: ViewSyncAttributesType): Promise<void> {
const logId = `ViewSyncs.onSync(timestamp=${viewSync.timestamp})`;
try {
const messages = await window.Signal.Data.getMessagesBySentAt(
viewSync.timestamp
);
const messages = await DataReader.getMessagesBySentAt(viewSync.timestamp);
const found = messages.find(item => {
const sender = window.ConversationController.lookupOrCreate({

View file

@ -4,6 +4,7 @@
import { omit } from 'lodash';
import * as log from '../logging/log';
import { DataReader, DataWriter } from '../sql/Client';
import type { QuotedMessageType } from '../model-types';
import type { MessageModel } from '../models/messages';
import { SignalService } from '../protobuf';
@ -50,7 +51,7 @@ export const copyFromQuotedMessage = async (
queryMessage = matchingMessage;
} else {
log.info('copyFromQuotedMessage: db lookup needed', id);
const messages = await window.Signal.Data.getMessagesBySentAt(id);
const messages = await DataReader.getMessagesBySentAt(id);
const found = messages.find(item =>
isQuoteAMatch(item, conversationId, result)
);
@ -142,7 +143,7 @@ export const copyQuoteContentFromOriginal = async (
originalMessage.attributes
);
originalMessage.set(upgradedMessage);
await window.Signal.Data.saveMessage(upgradedMessage, {
await DataWriter.saveMessage(upgradedMessage, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import * as log from '../logging/log';
import { DataReader } from '../sql/Client';
import type { MessageAttributesType } from '../model-types.d';
import * as Errors from '../types/errors';
import type { MessageModel } from '../models/messages';
@ -16,7 +17,7 @@ export async function __DEPRECATED$getMessageById(
let found: MessageAttributesType | undefined;
try {
found = await window.Signal.Data.getMessageById(messageId);
found = await DataReader.getMessageById(messageId);
} catch (err: unknown) {
log.error(
`failed to load message with id ${messageId} ` +

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import * as log from '../logging/log';
import { DataReader } from '../sql/Client';
import type { MessageModel } from '../models/messages';
import type { MessageAttributesType } from '../model-types.d';
import * as Errors from '../types/errors';
@ -23,7 +24,7 @@ export async function getMessagesById(
let rawMessagesFromDatabase: Array<MessageAttributesType>;
try {
rawMessagesFromDatabase = await window.Signal.Data.getMessagesById(
rawMessagesFromDatabase = await DataReader.getMessagesById(
messageIdsToLookUpInDatabase
);
} catch (err: unknown) {

View file

@ -15,6 +15,7 @@ import type {
QuotedMessageType,
SenderKeyInfoType,
} from '../model-types.d';
import { DataReader, DataWriter } from '../sql/Client';
import { getConversation } from '../util/getConversation';
import { drop } from '../util/drop';
import { isShallowEqual } from '../util/isShallowEqual';
@ -195,7 +196,6 @@ const {
writeNewAttachmentData,
} = window.Signal.Migrations;
const {
addStickerPackReference,
getConversationRangeCenteredOnMessage,
getOlderMessagesByConversation,
getMessageMetricsForConversation,
@ -203,7 +203,8 @@ const {
getMostRecentAddressableMessages,
getMostRecentAddressableNondisappearingMessages,
getNewerMessagesByConversation,
} = window.Signal.Data;
} = DataReader;
const { addStickerPackReference } = DataWriter;
const FIVE_MINUTES = MINUTE * 5;
const FETCH_TIMEOUT = SECOND * 30;
@ -471,7 +472,7 @@ export class ConversationModel extends window.Backbone
getSenderKeyInfo: () => this.get('senderKeyInfo'),
saveSenderKeyInfo: async (senderKeyInfo: SenderKeyInfoType) => {
this.set({ senderKeyInfo });
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
},
};
}
@ -828,7 +829,7 @@ export class ConversationModel extends window.Backbone
});
if (shouldSave) {
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
const e164 = this.get('e164');
@ -882,7 +883,7 @@ export class ConversationModel extends window.Backbone
});
if (shouldSave) {
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
if (
@ -1015,7 +1016,7 @@ export class ConversationModel extends window.Backbone
drop(this.queueJob('removeContact', () => this.maybeSetContactRemoved()));
if (shouldSave) {
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
}
@ -1048,7 +1049,7 @@ export class ConversationModel extends window.Backbone
await this.maybeClearContactRemoved();
if (shouldSave) {
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
}
@ -1239,7 +1240,7 @@ export class ConversationModel extends window.Backbone
this.set({ masterKey, secretParams, publicParams, groupVersion: 2 });
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
getGroupV2Info(
@ -1429,7 +1430,7 @@ export class ConversationModel extends window.Backbone
removalStage: 'messageRequest',
});
await this.maybeClearContactRemoved();
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
void this.addSingleMessage(message);
@ -1831,7 +1832,7 @@ export class ConversationModel extends window.Backbone
const upgradedMessage = await upgradeMessageSchema(attributes);
message.set(upgradedMessage);
// eslint-disable-next-line no-await-in-loop
await window.Signal.Data.saveMessage(upgradedMessage, { ourAci });
await DataWriter.saveMessage(upgradedMessage, { ourAci });
upgraded += 1;
}
}
@ -1900,7 +1901,7 @@ export class ConversationModel extends window.Backbone
void this.addChangeNumberNotification(oldValue, e164);
}
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
this.trigger('idUpdated', this, 'e164', oldValue);
this.captureChange('updateE164');
}
@ -1917,7 +1918,7 @@ export class ConversationModel extends window.Backbone
? normalizeServiceId(serviceId, 'Conversation.updateServiceId')
: undefined
);
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
this.trigger('idUpdated', this, 'serviceId', oldValue);
// We should delete the old sessions and identity information in all situations except
@ -1950,7 +1951,7 @@ export class ConversationModel extends window.Backbone
this.set({
previousIdentityKey: identityKey,
});
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
updatePni(pni: PniString | undefined, pniSignatureVerified: boolean): void {
@ -2025,7 +2026,7 @@ export class ConversationModel extends window.Backbone
);
}
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
this.trigger('idUpdated', this, 'pni', oldValue);
this.captureChange('updatePni');
}
@ -2034,7 +2035,7 @@ export class ConversationModel extends window.Backbone
const oldValue = this.get('groupId');
if (groupId && groupId !== oldValue) {
this.set('groupId', groupId);
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
this.trigger('idUpdated', this, 'groupId', oldValue);
}
}
@ -2048,14 +2049,14 @@ export class ConversationModel extends window.Backbone
}
this.set('reportingToken', newValue);
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
incrementMessageCount(): void {
this.set({
messageCount: (this.get('messageCount') || 0) + 1,
});
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
incrementSentMessageCount({ dry = false }: { dry?: boolean } = {}):
@ -2073,7 +2074,7 @@ export class ConversationModel extends window.Backbone
return update;
}
this.set(update);
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
return undefined;
}
@ -2093,7 +2094,7 @@ export class ConversationModel extends window.Backbone
const first = messages ? messages[0] : undefined;
// eslint-disable-next-line no-await-in-loop
messages = await window.Signal.Data.getOlderMessagesByConversation({
messages = await DataReader.getOlderMessagesByConversation({
conversationId: this.get('id'),
includeStoryReplies: !isGroup(this.attributes),
limit: 100,
@ -2143,7 +2144,7 @@ export class ConversationModel extends window.Backbone
);
const shouldSave = await registered.queueAttachmentDownloads();
if (shouldSave) {
await window.Signal.Data.saveMessage(registered.attributes, {
await DataWriter.saveMessage(registered.attributes, {
ourAci,
});
}
@ -2178,7 +2179,7 @@ export class ConversationModel extends window.Backbone
messageRequestResponseEvent: event,
};
const id = await window.Signal.Data.saveMessage(message, {
const id = await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -2358,7 +2359,7 @@ export class ConversationModel extends window.Backbone
}
} finally {
if (shouldSave) {
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
}
}
@ -2439,7 +2440,7 @@ export class ConversationModel extends window.Backbone
messageRequestResponseType: messageRequestEnum.ACCEPT,
active_at: this.get('active_at') || Date.now(),
});
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
async cancelJoinRequest(): Promise<void> {
@ -2631,7 +2632,7 @@ export class ConversationModel extends window.Backbone
if (oldVerified !== verified) {
this.set({ verified });
this.captureChange(`updateVerified from=${oldVerified} to=${verified}`);
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
return;
@ -2694,7 +2695,7 @@ export class ConversationModel extends window.Backbone
this.set({ verified });
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
if (beginningVerified !== verified) {
this.captureChange(
@ -2938,7 +2939,7 @@ export class ConversationModel extends window.Backbone
// this type does not fully implement the interface it is expected to
} as unknown as MessageAttributesType;
const id = await window.Signal.Data.saveMessage(message, {
const id = await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
const model = window.MessageCache.__DEPRECATED$register(
@ -2990,7 +2991,7 @@ export class ConversationModel extends window.Backbone
// this type does not fully implement the interface it is expected to
} as unknown as MessageAttributesType;
const id = await window.Signal.Data.saveMessage(message, {
const id = await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
const model = window.MessageCache.__DEPRECATED$register(
@ -3044,7 +3045,7 @@ export class ConversationModel extends window.Backbone
schemaVersion: Message.VERSION_NEEDED_FOR_DISPLAY,
};
await window.Signal.Data.saveMessage(message, {
await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -3108,7 +3109,7 @@ export class ConversationModel extends window.Backbone
schemaVersion: Message.VERSION_NEEDED_FOR_DISPLAY,
};
const id = await window.Signal.Data.saveMessage(message, {
const id = await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -3161,7 +3162,7 @@ export class ConversationModel extends window.Backbone
schemaVersion: Message.VERSION_NEEDED_FOR_DISPLAY,
};
const id = await window.Signal.Data.saveMessage(message, {
const id = await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -3212,7 +3213,7 @@ export class ConversationModel extends window.Backbone
verifiedChanged: verifiedChangeId,
};
await window.Signal.Data.saveMessage(message, {
await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -3255,7 +3256,7 @@ export class ConversationModel extends window.Backbone
// TODO: DESKTOP-722
} as unknown as MessageAttributesType;
const id = await window.Signal.Data.saveMessage(message, {
const id = await DataWriter.saveMessage(message, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
const model = window.MessageCache.__DEPRECATED$register(
@ -3300,7 +3301,7 @@ export class ConversationModel extends window.Backbone
...extra,
};
const id = await window.Signal.Data.saveMessage(
const id = await DataWriter.saveMessage(
// TODO: DESKTOP-722
message as MessageAttributesType,
{
@ -3395,7 +3396,7 @@ export class ConversationModel extends window.Backbone
const message = window.MessageCache.__DEPRECATED$getById(notificationId);
if (message) {
await window.Signal.Data.removeMessage(message.id, {
await DataWriter.removeMessage(message.id, {
singleProtoJobQueue,
});
}
@ -3422,7 +3423,7 @@ export class ConversationModel extends window.Backbone
'contact-removed-notification'
);
this.set('pendingRemovedContactNotification', notificationId);
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
async maybeClearContactRemoved(): Promise<boolean> {
@ -3438,7 +3439,7 @@ export class ConversationModel extends window.Backbone
const message = window.MessageCache.__DEPRECATED$getById(notificationId);
if (message) {
await window.Signal.Data.removeMessage(message.id, {
await DataWriter.removeMessage(message.id, {
singleProtoJobQueue,
});
}
@ -4015,7 +4016,7 @@ export class ConversationModel extends window.Backbone
log.info(
`enqueueMessageForSend: saving message ${message.id} and job ${jobToInsert.id}`
);
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
jobToInsert,
forceSave: true,
ourAci: window.textsecure.storage.user.getCheckedAci(),
@ -4063,7 +4064,7 @@ export class ConversationModel extends window.Backbone
);
}
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
return attributes;
}
@ -4127,7 +4128,7 @@ export class ConversationModel extends window.Backbone
});
}
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
this.captureChange('clearUsername');
}
@ -4152,7 +4153,7 @@ export class ConversationModel extends window.Backbone
this.captureChange('updateUsername');
if (shouldSave) {
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
}
@ -4169,7 +4170,7 @@ export class ConversationModel extends window.Backbone
const conversationId = this.id;
const stats = await window.Signal.Data.getConversationMessageStats({
const stats = await DataReader.getConversationMessageStats({
conversationId,
includeStoryReplies: !isGroup(this.attributes),
});
@ -4256,14 +4257,14 @@ export class ConversationModel extends window.Backbone
: false,
});
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
setArchived(isArchived: boolean): void {
const before = this.get('isArchived');
this.set({ isArchived });
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
const after = this.get('isArchived');
@ -4279,7 +4280,7 @@ export class ConversationModel extends window.Backbone
const previousMarkedUnread = this.get('markedUnread');
this.set({ markedUnread });
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
if (Boolean(previousMarkedUnread) !== Boolean(markedUnread)) {
this.captureChange('markedUnread');
@ -4562,7 +4563,7 @@ export class ConversationModel extends window.Backbone
// the pending flags.
await this.maybeRemoveUniversalTimer();
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
// When we add a disappearing messages notification to the conversation, we want it
// to be above the message that initiated that change, hence the subtraction.
@ -4596,7 +4597,7 @@ export class ConversationModel extends window.Backbone
type: 'timer-notification' as const,
};
await window.Signal.Data.saveMessage(attributes, {
await DataWriter.saveMessage(attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -4655,11 +4656,8 @@ export class ConversationModel extends window.Backbone
includeStoryReplies: !isGroup(this.attributes),
};
const [unreadCount, unreadMentionsCount] = await Promise.all([
window.Signal.Data.getTotalUnreadForConversation(this.id, options),
window.Signal.Data.getTotalUnreadMentionsOfMeForConversation(
this.id,
options
),
DataReader.getTotalUnreadForConversation(this.id, options),
DataReader.getTotalUnreadMentionsOfMeForConversation(this.id, options),
]);
const prevUnreadCount = this.get('unreadCount');
@ -4672,7 +4670,7 @@ export class ConversationModel extends window.Backbone
unreadCount,
unreadMentionsCount,
});
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
}
@ -4870,7 +4868,7 @@ export class ConversationModel extends window.Backbone
// We will update the conversation during storage service sync
if (!viaStorageServiceSync) {
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
return true;
@ -4971,7 +4969,7 @@ export class ConversationModel extends window.Backbone
this.set({ lastProfile: { profileKey, profileKeyVersion } });
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
async removeLastProfile(
@ -4997,7 +4995,7 @@ export class ConversationModel extends window.Backbone
profileAvatar: undefined,
});
await window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
}
hasMember(serviceId: ServiceIdString): boolean {
@ -5044,7 +5042,7 @@ export class ConversationModel extends window.Backbone
active_at: null,
pendingUniversalTimer: undefined,
});
window.Signal.Data.updateConversation(this.attributes);
await DataWriter.updateConversation(this.attributes);
const ourConversation =
window.ConversationController.getOurConversationOrThrow();
@ -5114,7 +5112,7 @@ export class ConversationModel extends window.Backbone
}
log.info(`${logId}: Starting delete`);
await window.Signal.Data.removeMessagesInConversation(this.id, {
await DataWriter.removeMessagesInConversation(this.id, {
fromSync: source !== 'local-delete-sync',
logId: this.idForLogging(),
singleProtoJobQueue,
@ -5227,7 +5225,7 @@ export class ConversationModel extends window.Backbone
);
this.set({ hideStory });
this.captureChange('hideStory');
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
setMuteExpiration(
@ -5247,7 +5245,7 @@ export class ConversationModel extends window.Backbone
if (!viaStorageServiceSync) {
this.captureChange('mutedUntilTimestamp');
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
}
@ -5572,7 +5570,7 @@ export class ConversationModel extends window.Backbone
if (this.get('isArchived')) {
this.set({ isArchived: false });
}
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
unpin(): void {
@ -5591,7 +5589,7 @@ export class ConversationModel extends window.Backbone
this.writePinnedConversations([...pinnedConversationIds]);
this.set('isPinned', false);
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
writePinnedConversations(pinnedConversationIds: Array<string>): void {
@ -5612,7 +5610,7 @@ export class ConversationModel extends window.Backbone
}
this.set({ dontNotifyForMentionsIfMuted: newValue });
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
this.captureChange('dontNotifyForMentionsIfMuted');
}
@ -5620,7 +5618,7 @@ export class ConversationModel extends window.Backbone
groupNameCollisions: ReadonlyDeep<GroupNameCollisionsWithIdsByTitle>
): void {
this.set('acknowledgedGroupNameCollisions', groupNameCollisions);
window.Signal.Data.updateConversation(this.attributes);
drop(DataWriter.updateConversation(this.attributes));
}
onOpenStart(): void {

View file

@ -134,7 +134,7 @@ import {
addToAttachmentDownloadQueue,
shouldUseAttachmentDownloadQueue,
} from '../util/attachmentDownloadQueue';
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import { shouldReplyNotifyUser } from '../util/shouldReplyNotifyUser';
import type { RawBodyRange } from '../types/BodyRange';
import { BodyRange } from '../types/BodyRange';
@ -163,7 +163,7 @@ window.Whisper = window.Whisper || {};
const { Message: TypedMessage } = window.Signal.Types;
const { upgradeMessageSchema } = window.Signal.Migrations;
const { getMessageBySender } = window.Signal.Data;
const { getMessageBySender } = DataReader;
export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
CURRENT_PROTOCOL_VERSION?: number;
@ -459,9 +459,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
isQuoteAMatch(message.attributes, this.get('conversationId'), quote)
);
if (!matchingMessage) {
const messages = await window.Signal.Data.getMessagesBySentAt(
Number(sentAt)
);
const messages = await DataReader.getMessagesBySentAt(Number(sentAt));
const found = messages.find(item =>
isQuoteAMatch(item, this.get('conversationId'), quote)
);
@ -540,12 +538,12 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
this.getConversation()?.debouncedUpdateLastMessage();
if (shouldPersist) {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
await window.Signal.Data.deleteSentProtoByMessageId(this.id);
await DataWriter.deleteSentProtoByMessageId(this.id);
}
override isEmpty(): boolean {
@ -675,7 +673,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
this.set({ errors });
if (!skipSave && !this.doNotSave) {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
@ -695,7 +693,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (storyDistributionListId) {
const storyDistribution =
await dataInterface.getStoryDistributionWithMembers(
await DataReader.getStoryDistributionWithMembers(
storyDistributionListId
);
@ -755,7 +753,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
timestamp: this.attributes.timestamp,
},
async jobToInsert => {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
jobToInsert,
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -770,7 +768,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
revision: conversation.get('revision'),
},
async jobToInsert => {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
jobToInsert,
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -918,7 +916,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
if (!this.doNotSave) {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
@ -1092,7 +1090,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
if (!this.doNotSave) {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}
@ -1151,7 +1149,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
throw error;
} finally {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -1305,7 +1303,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
return result;
}
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
return result;
@ -1521,7 +1519,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
sendStateByConversationId,
unidentifiedDeliveries: [...unidentifiedDeliveriesSet],
});
await window.Signal.Data.saveMessage(toUpdate.attributes, {
await DataWriter.saveMessage(toUpdate.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -1780,7 +1778,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
if (storyDistributionListId) {
const storyDistribution =
await dataInterface.getStoryDistributionWithMembers(
await DataReader.getStoryDistributionWithMembers(
storyDistributionListId
);
@ -2056,7 +2054,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
conversation.setArchived(false);
}
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
const giftBadge = message.get('giftBadge');
if (giftBadge) {
@ -2295,7 +2293,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
shouldSave: false,
});
// Note: generatedMessage comes with an id, so we have to force this save
await window.Signal.Data.saveMessage(generatedMessage.attributes, {
await DataWriter.saveMessage(generatedMessage.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -2320,9 +2318,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
targetConversation.set({
active_at: messageToAdd.get('timestamp'),
});
window.Signal.Data.updateConversation(
targetConversation.attributes
);
await DataWriter.updateConversation(targetConversation.attributes);
}
}
@ -2414,14 +2410,14 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
}
if (reaction.remove) {
await window.Signal.Data.removeReactionFromConversation({
await DataWriter.removeReactionFromConversation({
emoji: reaction.emoji,
fromId: reaction.fromId,
targetAuthorServiceId: reaction.targetAuthorAci,
targetTimestamp: reaction.targetTimestamp,
});
} else {
await window.Signal.Data.addReaction(
await DataWriter.addReaction(
{
conversationId: this.get('conversationId'),
emoji: reaction.emoji,
@ -2465,7 +2461,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
await generatedMessage.hydrateStoryContext(this.attributes, {
shouldSave: false,
});
await window.Signal.Data.saveMessage(generatedMessage.attributes, {
await DataWriter.saveMessage(generatedMessage.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
forceSave: true,
});
@ -2499,7 +2495,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
jobToInsert.id
}`
);
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
jobToInsert,
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
@ -2508,7 +2504,7 @@ export class MessageModel extends window.Backbone.Model<MessageAttributesType> {
await conversationJobQueue.add(jobData);
}
} else if (shouldPersist && !isStory(this.attributes)) {
await window.Signal.Data.saveMessage(this.attributes, {
await DataWriter.saveMessage(this.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -4,6 +4,7 @@
import noop from 'lodash/noop';
import { v4 as generateUuid } from 'uuid';
import { DataWriter } from '../sql/Client';
import type { ReactionAttributesType } from '../messageModifiers/Reactions';
import { ReactionSource } from './ReactionSource';
import { __DEPRECATED$getMessageById } from '../messages/getMessageById';
@ -63,9 +64,7 @@ export async function enqueueReactionForSend({
log.info('Enabling profile sharing for reaction send');
if (!messageConversation.get('profileSharing')) {
messageConversation.set('profileSharing', true);
await window.Signal.Data.updateConversation(
messageConversation.attributes
);
await DataWriter.updateConversation(messageConversation.attributes);
}
await messageConversation.restoreContact();
}

View file

@ -6,6 +6,7 @@ import { throttle } from 'lodash';
import LRU from 'lru-cache';
import type { MessageAttributesType } from '../model-types.d';
import type { MessageModel } from '../models/messages';
import { DataReader, DataWriter } from '../sql/Client';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
import { getEnvironment, Environment } from '../environment';
@ -152,7 +153,7 @@ export class MessageCache {
let messageAttributesFromDatabase: MessageAttributesType | undefined;
try {
messageAttributesFromDatabase = await window.Signal.Data.getMessageById(
messageAttributesFromDatabase = await DataReader.getMessageById(
messageId
);
} catch (err: unknown) {
@ -260,7 +261,7 @@ export class MessageCache {
return;
}
return window.Signal.Data.saveMessage(nextMessageAttributes, {
return DataWriter.saveMessage(nextMessageAttributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
}

View file

@ -9,7 +9,12 @@ import pTimeout from 'p-timeout';
import { Readable } from 'stream';
import { Backups, SignalService } from '../../protobuf';
import Data from '../../sql/Client';
import {
DataReader,
DataWriter,
pauseWriteAccess,
resumeWriteAccess,
} from '../../sql/Client';
import type { PageMessagesCursorType } from '../../sql/Interface';
import * as log from '../../logging/log';
import { GiftBadgeStates } from '../../components/conversation/Message';
@ -183,15 +188,16 @@ export class BackupExportStream extends Readable {
(async () => {
log.info('BackupExportStream: starting...');
drop(AttachmentBackupManager.stop());
await Data.pauseWriteAccess();
await pauseWriteAccess();
try {
await this.unsafeRun(backupLevel);
} catch (error) {
this.emit('error', error);
} finally {
await Data.resumeWriteAccess();
await resumeWriteAccess();
// TODO (DESKTOP-7344): Clear & add backup jobs in a single transaction
await Data.clearAllAttachmentBackupJobs();
await DataWriter.clearAllAttachmentBackupJobs();
await Promise.all(
this.attachmentBackupJobs.map(job =>
AttachmentBackupManager.addJobAndMaybeThumbnailJob(job)
@ -248,7 +254,8 @@ export class BackupExportStream extends Readable {
stats.conversations += 1;
}
const distributionLists = await Data.getAllStoryDistributionsWithMembers();
const distributionLists =
await DataReader.getAllStoryDistributionsWithMembers();
for (const list of distributionLists) {
const { PrivacyMode } = Backups.DistributionList;
@ -296,7 +303,7 @@ export class BackupExportStream extends Readable {
stats.distributionLists += 1;
}
const stickerPacks = await Data.getInstalledStickerPacks();
const stickerPacks = await DataReader.getInstalledStickerPacks();
for (const { id, key } of stickerPacks) {
this.pushFrame({
@ -379,7 +386,9 @@ export class BackupExportStream extends Readable {
try {
while (!cursor?.done) {
// eslint-disable-next-line no-await-in-loop
const { messages, cursor: newCursor } = await Data.pageMessages(cursor);
const { messages, cursor: newCursor } = await DataReader.pageMessages(
cursor
);
// eslint-disable-next-line no-await-in-loop
const items = await pMap(
@ -413,7 +422,7 @@ export class BackupExportStream extends Readable {
}
} finally {
if (cursor !== undefined) {
await Data.finishPageMessages(cursor);
await DataReader.finishPageMessages(cursor);
}
}

View file

@ -9,7 +9,7 @@ import { Writable } from 'stream';
import { isNumber } from 'lodash';
import { Backups, SignalService } from '../../protobuf';
import Data from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import type { StoryDistributionWithMembersType } from '../../sql/Interface';
import * as log from '../../logging/log';
import { GiftBadgeStates } from '../../components/conversation/Message';
@ -112,14 +112,14 @@ async function processConversationOpBatch(
`updates=${updates.length}`
);
await Data.saveConversations(saves);
await Data.updateConversations(updates);
await DataWriter.saveConversations(saves);
await DataWriter.updateConversations(updates);
}
async function processMessagesBatch(
ourAci: AciString,
batch: ReadonlyArray<MessageAttributesType>
): Promise<void> {
const ids = await Data.saveMessages(batch, {
const ids = await DataWriter.saveMessages(batch, {
forceSave: true,
ourAci,
});
@ -138,7 +138,7 @@ async function processMessagesBatch(
if (editHistory?.length) {
drop(
Data.saveEditedMessages(
DataWriter.saveEditedMessages(
attributes,
ourAci,
editHistory.slice(0, -1).map(({ timestamp }) => ({
@ -966,7 +966,7 @@ export class BackupImportStream extends Writable {
};
}
await Data.createNewStoryDistribution(result);
await DataWriter.createNewStoryDistribution(result);
}
private async fromChat(chat: Backups.IChat): Promise<void> {

View file

@ -12,6 +12,7 @@ import { createCipheriv, createHmac, randomBytes } from 'crypto';
import { noop } from 'lodash';
import { BackupLevel } from '@signalapp/libsignal-client/zkgroup';
import { DataReader, DataWriter } from '../../sql/Client';
import * as log from '../../logging/log';
import * as Bytes from '../../Bytes';
import { strictAssert } from '../../util/assert';
@ -187,7 +188,7 @@ export class BackupsService {
public async fetchAndSaveBackupCdnObjectMetadata(): Promise<void> {
log.info('fetchAndSaveBackupCdnObjectMetadata: clearing existing metadata');
await window.Signal.Data.clearAllBackupCdnObjectMetadata();
await DataWriter.clearAllBackupCdnObjectMetadata();
let cursor: string | undefined;
const PAGE_SIZE = 1000;
@ -198,7 +199,7 @@ export class BackupsService {
const listResult = await this.api.listMedia({ cursor, limit: PAGE_SIZE });
// eslint-disable-next-line no-await-in-loop
await window.Signal.Data.saveBackupCdnObjectMetadata(
await DataWriter.saveBackupCdnObjectMetadata(
listResult.storedMediaObjects.map(object => ({
mediaId: object.mediaId,
cdnNumber: object.cdn,
@ -220,9 +221,7 @@ export class BackupsService {
): Promise<
{ isInBackupTier: true; cdnNumber: number } | { isInBackupTier: false }
> {
const storedInfo = await window.Signal.Data.getBackupCdnObjectMetadata(
mediaId
);
const storedInfo = await DataReader.getBackupCdnObjectMetadata(mediaId);
if (!storedInfo) {
return { isInBackupTier: false };
}

View file

@ -1,6 +1,7 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import { DataReader } from '../../../sql/Client';
import * as Bytes from '../../../Bytes';
import { getBackupKey } from '../crypto';
import type { AttachmentType } from '../../../types/Attachment';
@ -63,9 +64,7 @@ export type GetBackupCdnInfoType = (
export const getBackupCdnInfo: GetBackupCdnInfoType = async (
mediaId: string
) => {
const savedInfo = await window.Signal.Data.getBackupCdnObjectMetadata(
mediaId
);
const savedInfo = await DataReader.getBackupCdnObjectMetadata(mediaId);
if (!savedInfo) {
return { isInBackupTier: false };
}

View file

@ -1,7 +1,7 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import type { CallHistoryDetails } from '../types/CallDisposition';
import { strictAssert } from '../util/assert';
@ -9,9 +9,9 @@ let callsHistoryData: ReadonlyArray<CallHistoryDetails>;
let callsHistoryUnreadCount: number;
export async function loadCallsHistory(): Promise<void> {
await dataInterface.cleanupCallHistoryMessages();
callsHistoryData = await dataInterface.getAllCallHistory();
callsHistoryUnreadCount = await dataInterface.getCallHistoryUnreadCount();
await DataWriter.cleanupCallHistoryMessages();
callsHistoryData = await DataReader.getAllCallHistory();
callsHistoryUnreadCount = await DataReader.getCallHistoryUnreadCount();
}
export function getCallsHistoryForRedux(): ReadonlyArray<CallHistoryDetails> {

View file

@ -1,14 +1,14 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import dataInterface from '../sql/Client';
import { DataReader } from '../sql/Client';
import type { CallLinkType } from '../types/CallLink';
import { strictAssert } from '../util/assert';
let callLinksData: ReadonlyArray<CallLinkType>;
export async function loadCallLinks(): Promise<void> {
callLinksData = await dataInterface.getAllCallLinks();
callLinksData = await DataReader.getAllCallLinks();
}
export function getCallLinksForRedux(): ReadonlyArray<CallLinkType> {

View file

@ -105,7 +105,7 @@ import { callingMessageToProto } from '../util/callingMessageToProto';
import { requestMicrophonePermissions } from '../util/requestMicrophonePermissions';
import OS from '../util/os/osMain';
import { SignalService as Proto } from '../protobuf';
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import {
notificationService,
NotificationSetting,
@ -159,11 +159,11 @@ import type {
import { CallLinkRestrictions } from '../types/CallLink';
import { getConversationIdForLogging } from '../util/idForLogging';
const { wasGroupCallRingPreviouslyCanceled } = DataReader;
const {
processGroupCallRingCancellation,
cleanExpiredGroupCallRingCancellations,
wasGroupCallRingPreviouslyCanceled,
} = dataInterface;
} = DataWriter;
const RINGRTC_HTTP_METHOD_TO_OUR_HTTP_METHOD: Map<
HttpMethod,
@ -933,7 +933,7 @@ export class CallingClass {
}
public async cleanupStaleRingingCalls(): Promise<void> {
const calls = await dataInterface.getRecentStaleRingsAndMarkOlderMissed();
const calls = await DataWriter.getRecentStaleRingsAndMarkOlderMissed();
const results = await Promise.all(
calls.map(async call => {
@ -950,7 +950,7 @@ export class CallingClass {
return result.callId;
});
await dataInterface.markCallHistoryMissed(staleCallIds);
await DataWriter.markCallHistoryMissed(staleCallIds);
}
public async peekGroupCall(conversationId: string): Promise<PeekInfo> {
@ -3281,11 +3281,10 @@ export class CallingClass {
return;
}
const prevMessageId =
await window.Signal.Data.getCallHistoryMessageByCallId({
conversationId: conversation.id,
callId: groupCallMeta.callId,
});
const prevMessageId = await DataReader.getCallHistoryMessageByCallId({
conversationId: conversation.id,
callId: groupCallMeta.callId,
});
const isNewCall = prevMessageId == null;

View file

@ -3,6 +3,7 @@
import PQueue from 'p-queue';
import { DataWriter } from '../sql/Client';
import type { ContactSyncEvent } from '../textsecure/messageReceiverEvents';
import type { ContactDetailsWithAvatar } from '../textsecure/ContactsParser';
import { normalizeAci } from '../util/normalizeAci';
@ -167,7 +168,7 @@ async function doContactSync({
// Save new conversation attributes
promises.push(
window.Signal.Data.updateConversations(
DataWriter.updateConversations(
[...updatedConversations, ...notUpdated].map(convo => convo.attributes)
)
);

View file

@ -1,7 +1,7 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import dataInterface from '../sql/Client';
import { DataReader } from '../sql/Client';
import type { StoryDistributionWithMembersType } from '../sql/Interface';
import type { StoryDistributionListDataType } from '../state/ducks/storyDistributionLists';
import { strictAssert } from '../util/assert';
@ -9,7 +9,7 @@ import { strictAssert } from '../util/assert';
let distributionLists: Array<StoryDistributionWithMembersType> | undefined;
export async function loadDistributionLists(): Promise<void> {
distributionLists = await dataInterface.getAllStoryDistributionsWithMembers();
distributionLists = await DataReader.getAllStoryDistributionsWithMembers();
}
export function getDistributionListsForRedux(): Array<StoryDistributionListDataType> {

View file

@ -4,6 +4,7 @@
import { batch } from 'react-redux';
import { debounce } from 'lodash';
import { DataReader, DataWriter } from '../sql/Client';
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
import { sleep } from '../util/sleep';
import { SECOND } from '../util/durations';
@ -27,7 +28,7 @@ class ExpiringMessagesDeletionService {
window.SignalContext.log.info(
'destroyExpiredMessages: Loading messages...'
);
const messages = await window.Signal.Data.getExpiredMessages();
const messages = await DataReader.getExpiredMessages();
window.SignalContext.log.info(
`destroyExpiredMessages: found ${messages.length} messages to expire`
);
@ -45,7 +46,7 @@ class ExpiringMessagesDeletionService {
inMemoryMessages.push(message);
});
await window.Signal.Data.removeMessages(messageIds, {
await DataWriter.removeMessages(messageIds, {
singleProtoJobQueue: this.singleProtoJobQueue,
});
@ -82,7 +83,7 @@ class ExpiringMessagesDeletionService {
'checkExpiringMessages: checking for expiring messages'
);
const soonestExpiry = await window.Signal.Data.getSoonestMessageExpiry();
const soonestExpiry = await DataReader.getSoonestMessageExpiry();
if (!soonestExpiry) {
window.SignalContext.log.info(
'checkExpiringMessages: found no messages to expire'

View file

@ -11,6 +11,7 @@ import type {
GetProfileUnauthOptionsType,
} from '../textsecure/WebAPI';
import type { ServiceIdString } from '../types/ServiceId';
import { DataWriter } from '../sql/Client';
import * as log from '../logging/log';
import * as Errors from '../types/errors';
import * as Bytes from '../Bytes';
@ -594,7 +595,7 @@ async function doGetProfile(c: ConversationModel): Promise<void> {
});
}
window.Signal.Data.updateConversation(c.attributes);
await DataWriter.updateConversation(c.attributes);
}
export type UpdateIdentityKeyOptionsType = Readonly<{

View file

@ -5,7 +5,7 @@ import { debounce, isNumber, chunk } from 'lodash';
import pMap from 'p-map';
import Long from 'long';
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import * as Bytes from '../Bytes';
import {
getRandomBytes,
@ -71,13 +71,14 @@ import { redactExtendedStorageID, redactStorageID } from '../util/privacy';
type IManifestRecordIdentifier = Proto.ManifestRecord.IIdentifier;
const { getItemById } = DataReader;
const {
eraseStorageServiceState,
flushUpdateConversationBatcher,
getItemById,
updateConversation,
updateConversations,
} = dataInterface;
} = DataWriter;
const uploadBucket: Array<number> = [];
@ -319,7 +320,7 @@ async function generateManifest(
storageVersion: version,
storageID,
});
updateConversation(conversation.attributes);
drop(updateConversation(conversation.attributes));
});
}
}
@ -360,7 +361,7 @@ async function generateManifest(
);
deleteKeys.add(droppedID);
drop(dataInterface.deleteStoryDistribution(storyDistributionList.id));
drop(DataWriter.deleteStoryDistribution(storyDistributionList.id));
continue;
}
@ -374,7 +375,7 @@ async function generateManifest(
if (isNewItem) {
postUploadUpdateFunctions.push(() => {
void dataInterface.modifyStoryDistribution({
void DataWriter.modifyStoryDistribution({
...storyDistributionList,
storageID,
storageVersion: version,
@ -407,7 +408,7 @@ async function generateManifest(
if (isNewItem) {
postUploadUpdateFunctions.push(() => {
void dataInterface.addUninstalledStickerPack({
void DataWriter.addUninstalledStickerPack({
...stickerPack,
storageID,
storageVersion: version,
@ -449,7 +450,7 @@ async function generateManifest(
if (isNewItem) {
postUploadUpdateFunctions.push(() => {
void dataInterface.createOrUpdateStickerPack({
void DataWriter.createOrUpdateStickerPack({
...stickerPack,
storageID,
storageVersion: version,
@ -1088,9 +1089,9 @@ async function getNonConversationRecords(): Promise<NonConversationRecordsResult
uninstalledStickerPacks,
installedStickerPacks,
] = await Promise.all([
dataInterface.getAllStoryDistributionsWithMembers(),
dataInterface.getUninstalledStickerPacks(),
dataInterface.getInstalledStickerPacks(),
DataReader.getAllStoryDistributionsWithMembers(),
DataReader.getUninstalledStickerPacks(),
DataReader.getInstalledStickerPacks(),
]);
return {
@ -1256,7 +1257,7 @@ async function processManifest(
}
conversation.unset('storageID');
conversation.unset('storageVersion');
updateConversation(conversation.attributes);
drop(updateConversation(conversation.attributes));
}
});
@ -1279,7 +1280,7 @@ async function processManifest(
`storageService.process(${version}): localKey=${missingKey} was not ` +
'in remote manifest'
);
void dataInterface.addUninstalledStickerPack({
void DataWriter.addUninstalledStickerPack({
...stickerPack,
storageID: undefined,
storageVersion: undefined,
@ -1297,7 +1298,7 @@ async function processManifest(
`storageService.process(${version}): localKey=${missingKey} was not ` +
'in remote manifest'
);
void dataInterface.createOrUpdateStickerPack({
void DataWriter.createOrUpdateStickerPack({
...stickerPack,
storageID: undefined,
storageVersion: undefined,
@ -1315,7 +1316,7 @@ async function processManifest(
`storageService.process(${version}): localKey=${missingKey} was not ` +
'in remote manifest'
);
void dataInterface.modifyStoryDistribution({
void DataWriter.modifyStoryDistribution({
...storyDistributionList,
storageID: undefined,
storageVersion: undefined,
@ -1339,7 +1340,7 @@ async function processManifest(
storageNeedsSync: true,
};
await dataInterface.createNewStoryDistribution(storyDistribution);
await DataWriter.createNewStoryDistribution(storyDistribution);
const shouldSave = false;
window.reduxActions.storyDistributionLists.createDistributionList(

View file

@ -59,7 +59,7 @@ import type {
StoryDistributionWithMembersType,
StickerPackInfoType,
} from '../sql/Interface';
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import { MY_STORY_ID, StorySendMode } from '../types/Stories';
import { findAndDeleteOnboardingStoryIfExists } from '../util/findAndDeleteOnboardingStoryIfExists';
import { downloadOnboardingStory } from '../util/downloadOnboardingStory';
@ -1682,7 +1682,7 @@ export async function mergeStoryDistributionListRecord(
}
const localStoryDistributionList =
await dataInterface.getStoryDistributionWithMembers(listId);
await DataReader.getStoryDistributionWithMembers(listId);
const remoteListMembers: Array<ServiceIdString> = (
storyDistributionListRecord.recipientServiceIds || []
@ -1714,7 +1714,7 @@ export async function mergeStoryDistributionListRecord(
};
if (!localStoryDistributionList) {
await dataInterface.createNewStoryDistribution(storyDistribution);
await DataWriter.createNewStoryDistribution(storyDistribution);
const shouldSave = false;
window.reduxActions.storyDistributionLists.createDistributionList(
@ -1766,7 +1766,7 @@ export async function mergeStoryDistributionListRecord(
);
details.push('updated');
await dataInterface.modifyStoryDistributionWithMembers(storyDistribution, {
await DataWriter.modifyStoryDistributionWithMembers(storyDistribution, {
toAdd,
toRemove,
});
@ -1804,7 +1804,7 @@ export async function mergeStickerPackRecord(
const details: Array<string> = [];
const id = Bytes.toHex(stickerPackRecord.packId);
const localStickerPack = await dataInterface.getStickerPackInfo(id);
const localStickerPack = await DataReader.getStickerPackInfo(id);
if (stickerPackRecord.$unknownFields) {
details.push('adding unknown fields');
@ -1897,7 +1897,7 @@ export async function mergeStickerPackRecord(
}
}
await dataInterface.updateStickerPackInfo(stickerPack);
await DataWriter.updateStickerPackInfo(stickerPack);
return {
details: [...details, ...conflictDetails],

View file

@ -6,7 +6,7 @@ import type { MessageAttributesType } from '../model-types.d';
import type { StoryDataType } from '../state/ducks/stories';
import * as durations from '../util/durations';
import * as log from '../logging/log';
import dataInterface from '../sql/Client';
import { DataReader, DataWriter } from '../sql/Client';
import type { GetAllStoriesResultType } from '../sql/Interface';
import {
getAttachmentsForMessage,
@ -22,7 +22,7 @@ import { SIGNAL_ACI } from '../types/SignalConversation';
let storyData: GetAllStoriesResultType | undefined;
export async function loadStories(): Promise<void> {
storyData = await dataInterface.getAllStories({});
storyData = await DataReader.getAllStories({});
await repairUnexpiredStories();
}
@ -171,7 +171,7 @@ async function repairUnexpiredStories(): Promise<void> {
await Promise.all(
storiesWithExpiry.map(messageAttributes => {
return window.Signal.Data.saveMessage(messageAttributes, {
return DataWriter.saveMessage(messageAttributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
});
})

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import { debounce } from 'lodash';
import { DataReader } from '../sql/Client';
import { clearTimeoutIfNecessary } from '../util/clearTimeoutIfNecessary';
import { DAY } from '../util/durations';
import * as Errors from '../types/errors';
@ -11,8 +12,7 @@ async function eraseTapToViewMessages() {
window.SignalContext.log.info(
'eraseTapToViewMessages: Loading messages...'
);
const messages =
await window.Signal.Data.getTapToViewMessagesNeedingErase();
const messages = await DataReader.getTapToViewMessagesNeedingErase();
await Promise.all(
messages.map(async fromDB => {
const message = window.MessageCache.__DEPRECATED$register(
@ -54,7 +54,7 @@ class TapToViewMessagesDeletionService {
private async checkTapToViewMessages() {
const receivedAt =
await window.Signal.Data.getNextTapToViewMessageTimestampToAgeOut();
await DataReader.getNextTapToViewMessageTimestampToAgeOut();
if (!receivedAt) {
return;
}

View file

@ -1,7 +1,7 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import dataInterface from '../sql/Client';
import { DataWriter } from '../sql/Client';
import type { ConversationType } from '../state/ducks/conversations';
import * as Errors from '../types/errors';
import * as log from '../logging/log';
@ -134,7 +134,7 @@ export async function writeProfile(
...maybeProfileAvatarUpdate,
});
dataInterface.updateConversation(model.attributes);
await DataWriter.updateConversation(model.attributes);
model.captureChange('writeProfile');
try {

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import * as log from '../logging/log';
import { DataWriter } from '../sql/Client';
import { deleteAllLogs } from '../util/deleteAllLogs';
import * as Errors from '../types/errors';
@ -11,19 +12,19 @@ export async function deleteAllData(): Promise<void> {
log.info('deleteAllData: deleted all logs');
await window.Signal.Data.removeAll();
await DataWriter.removeAll();
log.info('deleteAllData: emptied database');
await window.Signal.Data.close();
await DataWriter.close();
log.info('deleteAllData: closed database');
await window.Signal.Data.removeDB();
await DataWriter.removeDB();
log.info('deleteAllData: removed database');
await window.Signal.Data.removeOtherData();
await DataWriter.removeOtherData();
log.info('deleteAllData: removed all other data');
} catch (error) {

View file

@ -6,7 +6,6 @@
import * as Crypto from './Crypto';
import * as Curve from './Curve';
import { start as conversationControllerStart } from './ConversationController';
import Data from './sql/Client';
import * as Groups from './groups';
import OS from './util/os/osMain';
import * as RemoteConfig from './RemoteConfig';
@ -455,7 +454,6 @@ export const setup = (options: {
Curve,
// Note: used in test/index.html, and not type-checked!
conversationControllerStart,
Data,
Groups,
Migrations,
OS,

View file

@ -3,7 +3,7 @@
import { ipcRenderer as ipc } from 'electron';
import { has, get, groupBy, isTypedArray, last, map, omit } from 'lodash';
import { groupBy, isTypedArray, last, map, omit } from 'lodash';
import { deleteExternalFiles } from '../types/Conversation';
import { update as updateExpiringMessagesService } from '../services/expiringMessagesDeletion';
@ -23,13 +23,16 @@ import * as Errors from '../types/errors';
import type { StoredJob } from '../jobs/types';
import { formatJobForInsert } from '../jobs/formatJobForInsert';
import { cleanupMessages } from '../util/cleanup';
import { ipcInvoke, doShutdown } from './channels';
import { AccessType, ipcInvoke, doShutdown } from './channels';
import type {
ClientInterfaceWrap,
AdjacentMessagesByConversationOptionsType,
AllItemsType,
ClientInterface,
ClientExclusiveInterface,
ServerReadableDirectInterface,
ServerWritableDirectInterface,
ClientReadableInterface,
ClientWritableInterface,
ClientSearchResultMessageType,
ConversationType,
GetConversationRangeCenteredOnMessageResultType,
@ -45,13 +48,14 @@ import type {
PreKeyIdType,
PreKeyType,
StoredPreKeyType,
ServerInterface,
ServerSearchResultMessageType,
SignedPreKeyIdType,
SignedPreKeyType,
StoredSignedPreKeyType,
KyberPreKeyType,
StoredKyberPreKeyType,
ClientOnlyReadableInterface,
ClientOnlyWritableInterface,
} from './Interface';
import { getMessageIdForLogging } from '../util/idForLogging';
import type { MessageAttributesType } from '../model-types';
@ -67,44 +71,54 @@ const ERASE_TEMP_KEY = 'erase-temp';
const ERASE_DRAFTS_KEY = 'erase-drafts';
const CLEANUP_ORPHANED_ATTACHMENTS_KEY = 'cleanup-orphaned-attachments';
const ENSURE_FILE_PERMISSIONS = 'ensure-file-permissions';
const PAUSE_WRITE_ACCESS = 'pause-sql-writes';
const RESUME_WRITE_ACCESS = 'resume-sql-writes';
const exclusiveInterface: ClientExclusiveInterface = {
createOrUpdateIdentityKey,
const clientOnlyReadable: ClientOnlyReadableInterface = {
getIdentityKeyById,
bulkAddIdentityKeys,
getAllIdentityKeys,
createOrUpdateKyberPreKey,
getKyberPreKeyById,
bulkAddKyberPreKeys,
getAllKyberPreKeys,
createOrUpdatePreKey,
getPreKeyById,
bulkAddPreKeys,
getAllPreKeys,
createOrUpdateSignedPreKey,
getSignedPreKeyById,
bulkAddSignedPreKeys,
getAllSignedPreKeys,
createOrUpdateItem,
getItemById,
getAllItems,
searchMessages,
getRecentStoryReplies,
getOlderMessagesByConversation,
getNewerMessagesByConversation,
getConversationRangeCenteredOnMessage,
};
const clientOnlyWritable: ClientOnlyWritableInterface = {
createOrUpdateIdentityKey,
bulkAddIdentityKeys,
createOrUpdateKyberPreKey,
bulkAddKyberPreKeys,
createOrUpdatePreKey,
bulkAddPreKeys,
createOrUpdateSignedPreKey,
bulkAddSignedPreKeys,
createOrUpdateItem,
updateConversation,
removeConversation,
searchMessages,
removeMessage,
removeMessages,
getRecentStoryReplies,
getOlderMessagesByConversation,
getConversationRangeCenteredOnMessage,
getNewerMessagesByConversation,
// Client-side only
flushUpdateConversationBatcher,
@ -117,48 +131,82 @@ const exclusiveInterface: ClientExclusiveInterface = {
ensureFilePermissions,
};
type ClientOverridesType = ClientExclusiveInterface &
type ClientOverridesType = ClientOnlyWritableInterface &
Pick<
ServerInterface,
ClientInterfaceWrap<ServerWritableDirectInterface>,
| 'saveAttachmentDownloadJob'
| 'saveMessage'
| 'saveMessages'
| 'updateConversations'
>;
const channels: ServerInterface = new Proxy({} as ServerInterface, {
get(_target, name) {
return async (...args: ReadonlyArray<unknown>) =>
ipcInvoke(String(name), args);
},
});
const clientExclusiveOverrides: ClientOverridesType = {
...exclusiveInterface,
const clientOnlyWritableOverrides: ClientOverridesType = {
...clientOnlyWritable,
saveAttachmentDownloadJob,
saveMessage,
saveMessages,
updateConversations,
};
const dataInterface: ClientInterface = new Proxy(
type ReadableChannelInterface =
ClientInterfaceWrap<ServerReadableDirectInterface>;
const readableChannel: ReadableChannelInterface = new Proxy(
{} as ReadableChannelInterface,
{
...clientExclusiveOverrides,
} as ClientInterface,
get(_target, name) {
return async (...args: ReadonlyArray<unknown>) =>
ipcInvoke(AccessType.Read, String(name), args);
},
}
);
type WritableChannelInterface =
ClientInterfaceWrap<ServerWritableDirectInterface>;
const writableChannel: WritableChannelInterface = new Proxy(
{} as WritableChannelInterface,
{
get(_target, name) {
return async (...args: ReadonlyArray<unknown>) =>
ipcInvoke(AccessType.Write, String(name), args);
},
}
);
export const DataReader: ClientReadableInterface = new Proxy(
{
...clientOnlyReadable,
} as ClientReadableInterface,
{
get(target, name) {
return async (...args: ReadonlyArray<unknown>) => {
if (has(target, name)) {
return get(target, name)(...args);
if (Reflect.has(target, name)) {
return Reflect.get(target, name)(...args);
}
return get(channels, name)(...args);
return Reflect.get(readableChannel, name)(...args);
};
},
}
);
export default dataInterface;
export const DataWriter: ClientWritableInterface = new Proxy(
{
...clientOnlyWritableOverrides,
} as ClientWritableInterface,
{
get(target, name) {
return async (...args: ReadonlyArray<unknown>) => {
if (Reflect.has(target, name)) {
return Reflect.get(target, name)(...args);
}
return Reflect.get(writableChannel, name)(...args);
};
},
}
);
function _cleanData(
data: unknown
@ -246,9 +294,6 @@ async function shutdown(): Promise<void> {
// Stop accepting new SQL jobs, flush outstanding queue
await doShutdown();
// Close database
await channels.close();
}
// Identity Keys
@ -256,12 +301,12 @@ async function shutdown(): Promise<void> {
const IDENTITY_KEY_SPEC = ['publicKey'];
async function createOrUpdateIdentityKey(data: IdentityKeyType): Promise<void> {
const updated: StoredIdentityKeyType = specFromBytes(IDENTITY_KEY_SPEC, data);
await channels.createOrUpdateIdentityKey(updated);
await writableChannel.createOrUpdateIdentityKey(updated);
}
async function getIdentityKeyById(
id: IdentityKeyIdType
): Promise<IdentityKeyType | undefined> {
const data = await channels.getIdentityKeyById(id);
const data = await readableChannel.getIdentityKeyById(id);
return specToBytes(IDENTITY_KEY_SPEC, data);
}
@ -271,10 +316,10 @@ async function bulkAddIdentityKeys(
const updated: Array<StoredIdentityKeyType> = map(array, data =>
specFromBytes(IDENTITY_KEY_SPEC, data)
);
await channels.bulkAddIdentityKeys(updated);
await writableChannel.bulkAddIdentityKeys(updated);
}
async function getAllIdentityKeys(): Promise<Array<IdentityKeyType>> {
const keys = await channels.getAllIdentityKeys();
const keys = await readableChannel.getAllIdentityKeys();
return keys.map(key => specToBytes(IDENTITY_KEY_SPEC, key));
}
@ -287,12 +332,12 @@ async function createOrUpdateKyberPreKey(data: KyberPreKeyType): Promise<void> {
KYBER_PRE_KEY_SPEC,
data
);
await channels.createOrUpdateKyberPreKey(updated);
await writableChannel.createOrUpdateKyberPreKey(updated);
}
async function getKyberPreKeyById(
id: PreKeyIdType
): Promise<KyberPreKeyType | undefined> {
const data = await channels.getPreKeyById(id);
const data = await readableChannel.getPreKeyById(id);
return specToBytes(KYBER_PRE_KEY_SPEC, data);
}
@ -302,10 +347,10 @@ async function bulkAddKyberPreKeys(
const updated: Array<StoredKyberPreKeyType> = map(array, data =>
specFromBytes(KYBER_PRE_KEY_SPEC, data)
);
await channels.bulkAddKyberPreKeys(updated);
await writableChannel.bulkAddKyberPreKeys(updated);
}
async function getAllKyberPreKeys(): Promise<Array<KyberPreKeyType>> {
const keys = await channels.getAllKyberPreKeys();
const keys = await readableChannel.getAllKyberPreKeys();
return keys.map(key => specToBytes(KYBER_PRE_KEY_SPEC, key));
}
@ -314,12 +359,12 @@ async function getAllKyberPreKeys(): Promise<Array<KyberPreKeyType>> {
async function createOrUpdatePreKey(data: PreKeyType): Promise<void> {
const updated: StoredPreKeyType = specFromBytes(PRE_KEY_SPEC, data);
await channels.createOrUpdatePreKey(updated);
await writableChannel.createOrUpdatePreKey(updated);
}
async function getPreKeyById(
id: PreKeyIdType
): Promise<PreKeyType | undefined> {
const data = await channels.getPreKeyById(id);
const data = await readableChannel.getPreKeyById(id);
return specToBytes(PRE_KEY_SPEC, data);
}
@ -327,10 +372,10 @@ async function bulkAddPreKeys(array: Array<PreKeyType>): Promise<void> {
const updated: Array<StoredPreKeyType> = map(array, data =>
specFromBytes(PRE_KEY_SPEC, data)
);
await channels.bulkAddPreKeys(updated);
await writableChannel.bulkAddPreKeys(updated);
}
async function getAllPreKeys(): Promise<Array<PreKeyType>> {
const keys = await channels.getAllPreKeys();
const keys = await readableChannel.getAllPreKeys();
return keys.map(key => specToBytes(PRE_KEY_SPEC, key));
}
@ -342,17 +387,17 @@ async function createOrUpdateSignedPreKey(
data: SignedPreKeyType
): Promise<void> {
const updated: StoredSignedPreKeyType = specFromBytes(PRE_KEY_SPEC, data);
await channels.createOrUpdateSignedPreKey(updated);
await writableChannel.createOrUpdateSignedPreKey(updated);
}
async function getSignedPreKeyById(
id: SignedPreKeyIdType
): Promise<SignedPreKeyType | undefined> {
const data = await channels.getSignedPreKeyById(id);
const data = await readableChannel.getSignedPreKeyById(id);
return specToBytes(PRE_KEY_SPEC, data);
}
async function getAllSignedPreKeys(): Promise<Array<SignedPreKeyType>> {
const keys = await channels.getAllSignedPreKeys();
const keys = await readableChannel.getAllSignedPreKeys();
return keys.map(key => specToBytes(PRE_KEY_SPEC, key));
}
@ -362,7 +407,7 @@ async function bulkAddSignedPreKeys(
const updated: Array<StoredSignedPreKeyType> = map(array, data =>
specFromBytes(PRE_KEY_SPEC, data)
);
await channels.bulkAddSignedPreKeys(updated);
await writableChannel.bulkAddSignedPreKeys(updated);
}
// Items
@ -398,13 +443,13 @@ async function createOrUpdateItem<K extends ItemKeyType>(
? specFromBytes(spec, data)
: (data as unknown as StoredItemType<K>);
await channels.createOrUpdateItem(updated);
await writableChannel.createOrUpdateItem(updated);
}
async function getItemById<K extends ItemKeyType>(
id: K
): Promise<ItemType<K> | undefined> {
const spec = ITEM_SPECS[id];
const data = await channels.getItemById(id);
const data = await readableChannel.getItemById(id);
try {
return spec ? specToBytes(spec, data) : (data as unknown as ItemType<K>);
@ -414,7 +459,7 @@ async function getItemById<K extends ItemKeyType>(
}
}
async function getAllItems(): Promise<AllItemsType> {
const items = await channels.getAllItems();
const items = await readableChannel.getAllItems();
const result = Object.create(null);
@ -458,7 +503,7 @@ const updateConversationBatcher = createBatcher<ConversationType>({
},
});
function updateConversation(data: ConversationType): void {
async function updateConversation(data: ConversationType): Promise<void> {
updateConversationBatcher.add(data);
}
async function flushUpdateConversationBatcher(): Promise<void> {
@ -473,16 +518,16 @@ async function updateConversations(
!pathsChanged.length,
`Paths were cleaned: ${JSON.stringify(pathsChanged)}`
);
await channels.updateConversations(cleaned);
await writableChannel.updateConversations(cleaned);
}
async function removeConversation(id: string): Promise<void> {
const existing = await channels.getConversationById(id);
const existing = await readableChannel.getConversationById(id);
// Note: It's important to have a fully database-hydrated model to delete here because
// it needs to delete all associated on-disk files along with the database delete.
if (existing) {
await channels.removeConversation(id);
await writableChannel.removeConversation(id);
await deleteExternalFiles(existing, {
deleteAttachmentData: window.Signal.Migrations.deleteAttachmentData,
});
@ -528,7 +573,7 @@ async function searchMessages({
contactServiceIdsMatchingQuery?: Array<ServiceIdString>;
conversationId?: string;
}): Promise<Array<ClientSearchResultMessageType>> {
const messages = await channels.searchMessages({
const messages = await readableChannel.searchMessages({
query,
conversationId,
options,
@ -548,7 +593,7 @@ async function saveMessage(
ourAci: AciString;
}
): Promise<string> {
const id = await channels.saveMessage(_cleanMessageData(data), {
const id = await writableChannel.saveMessage(_cleanMessageData(data), {
...options,
jobToInsert: options.jobToInsert && formatJobForInsert(options.jobToInsert),
});
@ -565,7 +610,7 @@ async function saveMessages(
arrayOfMessages: ReadonlyArray<MessageType>,
options: { forceSave?: boolean; ourAci: AciString }
): Promise<Array<string>> {
const result = await channels.saveMessages(
const result = await writableChannel.saveMessages(
arrayOfMessages.map(message => _cleanMessageData(message)),
options
);
@ -583,15 +628,15 @@ async function removeMessage(
fromSync?: boolean;
}
): Promise<void> {
const message = await channels.getMessageById(id);
const message = await readableChannel.getMessageById(id);
// Note: It's important to have a fully database-hydrated model to delete here because
// it needs to delete all associated on-disk files along with the database delete.
if (message) {
await channels.removeMessage(id);
await writableChannel.removeMessage(id);
await cleanupMessages([message], {
...options,
markCallHistoryDeleted: dataInterface.markCallHistoryDeleted,
markCallHistoryDeleted: DataWriter.markCallHistoryDeleted,
});
}
}
@ -607,12 +652,12 @@ export async function deleteAndCleanup(
const ids = messages.map(message => message.id);
log.info(`deleteAndCleanup/${logId}: Deleting ${ids.length} messages...`);
await channels.removeMessages(ids);
await writableChannel.removeMessages(ids);
log.info(`deleteAndCleanup/${logId}: Cleanup for ${ids.length} messages...`);
await cleanupMessages(messages, {
...options,
markCallHistoryDeleted: dataInterface.markCallHistoryDeleted,
markCallHistoryDeleted: DataWriter.markCallHistoryDeleted,
});
log.info(`deleteAndCleanup/${logId}: Complete`);
@ -625,12 +670,12 @@ async function removeMessages(
singleProtoJobQueue: SingleProtoJobQueue;
}
): Promise<void> {
const messages = await channels.getMessagesById(messageIds);
const messages = await readableChannel.getMessagesById(messageIds);
await cleanupMessages(messages, {
...options,
markCallHistoryDeleted: dataInterface.markCallHistoryDeleted,
markCallHistoryDeleted: DataWriter.markCallHistoryDeleted,
});
await channels.removeMessages(messageIds);
await writableChannel.removeMessages(messageIds);
}
function handleMessageJSON(
@ -642,7 +687,9 @@ function handleMessageJSON(
async function getNewerMessagesByConversation(
options: AdjacentMessagesByConversationOptionsType
): Promise<Array<MessageType>> {
const messages = await channels.getNewerMessagesByConversation(options);
const messages = await readableChannel.getNewerMessagesByConversation(
options
);
return handleMessageJSON(messages);
}
@ -651,7 +698,10 @@ async function getRecentStoryReplies(
storyId: string,
options?: GetRecentStoryRepliesOptionsType
): Promise<Array<MessageType>> {
const messages = await channels.getRecentStoryReplies(storyId, options);
const messages = await readableChannel.getRecentStoryReplies(
storyId,
options
);
return handleMessageJSON(messages);
}
@ -659,7 +709,9 @@ async function getRecentStoryReplies(
async function getOlderMessagesByConversation(
options: AdjacentMessagesByConversationOptionsType
): Promise<Array<MessageType>> {
const messages = await channels.getOlderMessagesByConversation(options);
const messages = await readableChannel.getOlderMessagesByConversation(
options
);
return handleMessageJSON(messages);
}
@ -667,7 +719,9 @@ async function getOlderMessagesByConversation(
async function getConversationRangeCenteredOnMessage(
options: AdjacentMessagesByConversationOptionsType
): Promise<GetConversationRangeCenteredOnMessageResultType<MessageType>> {
const result = await channels.getConversationRangeCenteredOnMessage(options);
const result = await readableChannel.getConversationRangeCenteredOnMessage(
options
);
return {
...result,
@ -721,7 +775,7 @@ async function removeMessagesInConversation(
async function saveAttachmentDownloadJob(
job: AttachmentDownloadJobType
): Promise<void> {
await channels.saveAttachmentDownloadJob(_cleanData(job));
await writableChannel.saveAttachmentDownloadJob(_cleanData(job));
}
// Other
@ -758,3 +812,11 @@ async function invokeWithTimeout(name: string): Promise<void> {
`callChannel call to ${name}`
)();
}
export function pauseWriteAccess(): Promise<void> {
return invokeWithTimeout(PAUSE_WRITE_ACCESS);
}
export function resumeWriteAccess(): Promise<void> {
return invokeWithTimeout(RESUME_WRITE_ACCESS);
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -5,13 +5,21 @@ import { ipcRenderer } from 'electron';
import * as log from '../logging/log';
import createTaskWithTimeout from '../textsecure/TaskWithTimeout';
import { explodePromise } from '../util/explodePromise';
import { missingCaseError } from '../util/missingCaseError';
const SQL_CHANNEL_KEY = 'sql-channel';
const SQL_READ_KEY = 'sql-channel:read';
const SQL_WRITE_KEY = 'sql-channel:write';
let activeJobCount = 0;
let resolveShutdown: (() => void) | undefined;
let shutdownPromise: Promise<void> | null = null;
export enum AccessType {
Read = 'Read',
Write = 'Write',
}
export async function ipcInvoke<T>(
access: AccessType,
name: string,
args: ReadonlyArray<unknown>
): Promise<T> {
@ -19,21 +27,31 @@ export async function ipcInvoke<T>(
if (shutdownPromise && name !== 'close') {
throw new Error(
`Rejecting SQL channel job (${fnName}); application is shutting down`
`Rejecting SQL channel job (${access}, ${fnName}); ` +
'application is shutting down'
);
}
let channel: string;
if (access === AccessType.Read) {
channel = SQL_READ_KEY;
} else if (access === AccessType.Write) {
channel = SQL_WRITE_KEY;
} else {
throw missingCaseError(access);
}
activeJobCount += 1;
return createTaskWithTimeout(async () => {
try {
return await ipcRenderer.invoke(SQL_CHANNEL_KEY, name, ...args);
return await ipcRenderer.invoke(channel, name, ...args);
} finally {
activeJobCount -= 1;
if (activeJobCount === 0) {
resolveShutdown?.();
}
}
}, `SQL channel call (${fnName})`)();
}, `SQL channel call (${access}, ${fnName})`)();
}
export async function doShutdown(): Promise<void> {

View file

@ -10,10 +10,15 @@ import { strictAssert } from '../util/assert';
import { explodePromise } from '../util/explodePromise';
import type { LoggerType } from '../types/Logging';
import { SqliteErrorKind } from './errors';
import type DB from './Server';
import type {
ServerReadableDirectInterface,
ServerWritableDirectInterface,
} from './Interface';
const MIN_TRACE_DURATION = 40;
const WORKER_COUNT = 4;
export type InitializeOptions = Readonly<{
appVersion: string;
configDir: string;
@ -25,16 +30,19 @@ export type WorkerRequest = Readonly<
| {
type: 'init';
options: Omit<InitializeOptions, 'logger'>;
isPrimary: boolean;
}
| {
type: 'close';
type: 'close' | 'removeDB';
}
| {
type: 'removeDB';
type: 'sqlCall:read';
method: keyof ServerReadableDirectInterface;
args: ReadonlyArray<unknown>;
}
| {
type: 'sqlCall';
method: keyof typeof DB;
type: 'sqlCall:write';
method: keyof ServerWritableDirectInterface;
args: ReadonlyArray<unknown>;
}
>;
@ -71,14 +79,26 @@ type KnownErrorResolverType = Readonly<{
resolve: (err: Error) => void;
}>;
type CreateWorkerResultType = Readonly<{
worker: Worker;
onExit: Promise<void>;
}>;
type PoolEntry = {
readonly worker: Worker;
load: number;
};
export class MainSQL {
private readonly worker: Worker;
private readonly pool = new Array<PoolEntry>();
private pauseWaiters: Array<() => void> | undefined;
private isReady = false;
private onReady: Promise<void> | undefined;
private readonly onExit: Promise<void>;
private readonly onExit: Promise<unknown>;
// Promise resolve callbacks for corruption and readonly errors.
private errorResolvers = new Array<KnownErrorResolverType>();
@ -93,10 +113,246 @@ export class MainSQL {
private shouldTimeQueries = false;
constructor() {
const scriptDir = join(app.getAppPath(), 'ts', 'sql', 'mainWorker.js');
this.worker = new Worker(scriptDir);
const exitPromises = new Array<Promise<void>>();
for (let i = 0; i < WORKER_COUNT; i += 1) {
const { worker, onExit } = this.createWorker();
this.pool.push({ worker, load: 0 });
this.worker.on('message', (wrappedResponse: WrappedWorkerResponse) => {
exitPromises.push(onExit);
}
this.onExit = Promise.all(exitPromises);
}
public async initialize({
appVersion,
configDir,
key,
logger,
}: InitializeOptions): Promise<void> {
if (this.isReady || this.onReady) {
throw new Error('Already initialized');
}
this.shouldTimeQueries = Boolean(process.env.TIME_QUERIES);
this.logger = logger;
this.onReady = (async () => {
const primary = this.pool[0];
const rest = this.pool.slice(1);
await this.send(primary, {
type: 'init',
options: { appVersion, configDir, key },
isPrimary: true,
});
await Promise.all(
rest.map(worker =>
this.send(worker, {
type: 'init',
options: { appVersion, configDir, key },
isPrimary: false,
})
)
);
})();
await this.onReady;
this.onReady = undefined;
this.isReady = true;
}
public pauseWriteAccess(): void {
strictAssert(this.pauseWaiters == null, 'Already paused');
this.pauseWaiters = [];
}
public resumeWriteAccess(): void {
const { pauseWaiters } = this;
strictAssert(pauseWaiters != null, 'Not paused');
this.pauseWaiters = undefined;
for (const waiter of pauseWaiters) {
waiter();
}
}
public whenCorrupted(): Promise<Error> {
const { promise, resolve } = explodePromise<Error>();
this.errorResolvers.push({ kind: SqliteErrorKind.Corrupted, resolve });
return promise;
}
public whenReadonly(): Promise<Error> {
const { promise, resolve } = explodePromise<Error>();
this.errorResolvers.push({ kind: SqliteErrorKind.Readonly, resolve });
return promise;
}
public async close(): Promise<void> {
if (!this.isReady) {
throw new Error('Not initialized');
}
await this.terminate({ type: 'close' });
await this.onExit;
}
public async removeDB(): Promise<void> {
await this.terminate({ type: 'removeDB' });
}
public async sqlRead<Method extends keyof ServerReadableDirectInterface>(
method: Method,
...args: Parameters<ServerReadableDirectInterface[Method]>
): Promise<ReturnType<ServerReadableDirectInterface[Method]>> {
type SqlCallResult = Readonly<{
result: ReturnType<ServerReadableDirectInterface[Method]>;
duration: number;
}>;
// pageMessages runs over several queries and needs to have access to
// the same temporary table.
const isPaging = method === 'pageMessages';
const entry = isPaging ? this.pool.at(-1) : this.getWorker();
strictAssert(entry != null, 'Must have a pool entry');
const { result, duration } = await this.send<SqlCallResult>(entry, {
type: 'sqlCall:read',
method,
args,
});
this.traceDuration(method, duration);
return result;
}
public async sqlWrite<Method extends keyof ServerWritableDirectInterface>(
method: Method,
...args: Parameters<ServerWritableDirectInterface[Method]>
): Promise<ReturnType<ServerWritableDirectInterface[Method]>> {
type Result = ReturnType<ServerWritableDirectInterface[Method]>;
type SqlCallResult = Readonly<{
result: Result;
duration: number;
}>;
while (this.pauseWaiters != null) {
const { promise, resolve } = explodePromise<void>();
this.pauseWaiters.push(resolve);
// eslint-disable-next-line no-await-in-loop
await promise;
}
// Special case since we need to broadcast this to every pool entry.
if (method === 'removeDB') {
return (await this.removeDB()) as Result;
}
const primary = this.pool[0];
const { result, duration } = await this.send<SqlCallResult>(primary, {
type: 'sqlCall:write',
method,
args,
});
this.traceDuration(method, duration);
return result;
}
private async send<Response>(
entry: PoolEntry,
request: WorkerRequest
): Promise<Response> {
if (request.type === 'sqlCall:read' || request.type === 'sqlCall:write') {
if (this.onReady) {
await this.onReady;
}
if (!this.isReady) {
throw new Error('Not initialized');
}
}
const { seq } = this;
// eslint-disable-next-line no-bitwise
this.seq = (this.seq + 1) >>> 0;
const { promise: result, resolve, reject } = explodePromise<Response>();
this.onResponse.set(seq, { resolve, reject });
const wrappedRequest: WrappedWorkerRequest = {
seq,
request,
};
entry.worker.postMessage(wrappedRequest);
try {
// eslint-disable-next-line no-param-reassign
entry.load += 1;
return await result;
} finally {
// eslint-disable-next-line no-param-reassign
entry.load -= 1;
}
}
private async terminate(request: WorkerRequest): Promise<void> {
const primary = this.pool[0];
const rest = this.pool.slice(1);
// Terminate non-primary workers first
await Promise.all(rest.map(worker => this.send(worker, request)));
// Primary last
await this.send(primary, request);
}
private onError(errorKind: SqliteErrorKind, error: Error): void {
if (errorKind === SqliteErrorKind.Unknown) {
return;
}
const resolvers = new Array<(error: Error) => void>();
this.errorResolvers = this.errorResolvers.filter(entry => {
if (entry.kind === errorKind) {
resolvers.push(entry.resolve);
return false;
}
return true;
});
for (const resolve of resolvers) {
resolve(error);
}
}
private traceDuration(method: string, duration: number): void {
if (this.shouldTimeQueries && !app.isPackaged) {
const twoDecimals = Math.round(100 * duration) / 100;
this.logger?.info(`MainSQL query: ${method}, duration=${twoDecimals}ms`);
}
if (duration > MIN_TRACE_DURATION) {
strictAssert(this.logger !== undefined, 'Logger not initialized');
this.logger.info(
`MainSQL: slow query ${method} duration=${Math.round(duration)}ms`
);
}
}
private createWorker(): CreateWorkerResultType {
const scriptPath = join(app.getAppPath(), 'ts', 'sql', 'mainWorker.js');
const worker = new Worker(scriptPath);
worker.on('message', (wrappedResponse: WrappedWorkerResponse) => {
if (wrappedResponse.type === 'log') {
const { level, args } = wrappedResponse;
strictAssert(this.logger !== undefined, 'Logger not initialized');
@ -123,129 +379,21 @@ export class MainSQL {
});
const { promise: onExit, resolve: resolveOnExit } = explodePromise<void>();
this.onExit = onExit;
this.worker.once('exit', resolveOnExit);
worker.once('exit', resolveOnExit);
return { worker, onExit };
}
public async initialize({
appVersion,
configDir,
key,
logger,
}: InitializeOptions): Promise<void> {
if (this.isReady || this.onReady) {
throw new Error('Already initialized');
}
this.shouldTimeQueries = Boolean(process.env.TIME_QUERIES);
this.logger = logger;
this.onReady = this.send({
type: 'init',
options: { appVersion, configDir, key },
});
await this.onReady;
this.onReady = undefined;
this.isReady = true;
}
public whenCorrupted(): Promise<Error> {
const { promise, resolve } = explodePromise<Error>();
this.errorResolvers.push({ kind: SqliteErrorKind.Corrupted, resolve });
return promise;
}
public whenReadonly(): Promise<Error> {
const { promise, resolve } = explodePromise<Error>();
this.errorResolvers.push({ kind: SqliteErrorKind.Readonly, resolve });
return promise;
}
public async close(): Promise<void> {
if (!this.isReady) {
throw new Error('Not initialized');
}
await this.send({ type: 'close' });
await this.onExit;
}
public async removeDB(): Promise<void> {
await this.send({ type: 'removeDB' });
}
public async sqlCall<Method extends keyof typeof DB>(
method: Method,
...args: Parameters<typeof DB[Method]>
): Promise<ReturnType<typeof DB[Method]>> {
if (this.onReady) {
await this.onReady;
}
if (!this.isReady) {
throw new Error('Not initialized');
}
type SqlCallResult = Readonly<{
result: ReturnType<typeof DB[Method]>;
duration: number;
}>;
const { result, duration } = await this.send<SqlCallResult>({
type: 'sqlCall',
method,
args,
});
if (this.shouldTimeQueries && !app.isPackaged) {
const twoDecimals = Math.round(100 * duration) / 100;
this.logger?.info(`MainSQL query: ${method}, duration=${twoDecimals}ms`);
}
if (duration > MIN_TRACE_DURATION) {
strictAssert(this.logger !== undefined, 'Logger not initialized');
this.logger.info(
`MainSQL: slow query ${method} duration=${Math.round(duration)}ms`
);
}
return result;
}
private async send<Response>(request: WorkerRequest): Promise<Response> {
const { seq } = this;
this.seq += 1;
const { promise: result, resolve, reject } = explodePromise<Response>();
this.onResponse.set(seq, { resolve, reject });
const wrappedRequest: WrappedWorkerRequest = {
seq,
request,
};
this.worker.postMessage(wrappedRequest);
return result;
}
private onError(errorKind: SqliteErrorKind, error: Error): void {
if (errorKind === SqliteErrorKind.Unknown) {
return;
}
const resolvers = new Array<(error: Error) => void>();
this.errorResolvers = this.errorResolvers.filter(entry => {
if (entry.kind === errorKind) {
resolvers.push(entry.resolve);
return false;
// Find first pool entry with minimal load
private getWorker(): PoolEntry {
let min = this.pool[0];
for (const entry of this.pool) {
if (min && min.load < entry.load) {
continue;
}
return true;
});
for (const resolve of resolvers) {
resolve(error);
min = entry;
}
return min;
}
}

View file

@ -10,7 +10,8 @@ import type {
WrappedWorkerResponse,
WrappedWorkerLogEntry,
} from './main';
import db from './Server';
import type { WritableDB } from './Interface';
import { initialize, DataReader, DataWriter } from './Server';
import { SqliteErrorKind, parseSqliteError } from './errors';
if (!parentPort) {
@ -27,8 +28,8 @@ function respond(seq: number, error: Error | undefined, response?: any) {
errorKind = parseSqliteError(error);
errorString = Errors.toLogFormat(error);
if (errorKind === SqliteErrorKind.Corrupted) {
db.runCorruptionChecks();
if (errorKind === SqliteErrorKind.Corrupted && db != null) {
DataWriter.runCorruptionChecks(db);
}
}
@ -75,11 +76,18 @@ const logger: LoggerType = {
},
};
port.on('message', async ({ seq, request }: WrappedWorkerRequest) => {
let db: WritableDB | undefined;
let isPrimary = false;
let isRemoved = false;
port.on('message', ({ seq, request }: WrappedWorkerRequest) => {
try {
if (request.type === 'init') {
await db.initialize({
isPrimary = request.isPrimary;
isRemoved = false;
db = initialize({
...request.options,
isPrimary,
logger,
});
@ -87,8 +95,24 @@ port.on('message', async ({ seq, request }: WrappedWorkerRequest) => {
return;
}
// 'close' is sent on shutdown, but we already removed the database.
if (isRemoved && request.type === 'close') {
respond(seq, undefined, undefined);
process.exit(0);
return;
}
if (!db) {
throw new Error('Not initialized');
}
if (request.type === 'close') {
await db.close();
if (isPrimary) {
DataWriter.close(db);
} else {
DataReader.close(db);
}
db = undefined;
respond(seq, undefined, undefined);
process.exit(0);
@ -96,21 +120,30 @@ port.on('message', async ({ seq, request }: WrappedWorkerRequest) => {
}
if (request.type === 'removeDB') {
await db.removeDB();
if (isPrimary) {
DataWriter.removeDB(db);
} else {
DataReader.close(db);
}
isRemoved = true;
db = undefined;
respond(seq, undefined, undefined);
return;
}
if (request.type === 'sqlCall') {
if (request.type === 'sqlCall:read' || request.type === 'sqlCall:write') {
const DataInterface =
request.type === 'sqlCall:read' ? DataReader : DataWriter;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const method = (db as any)[request.method];
const method = (DataInterface as any)[request.method];
if (typeof method !== 'function') {
throw new Error(`Invalid sql method: ${method}`);
}
const start = performance.now();
const result = await method.apply(db, request.args);
const result = method(db, ...request.args);
const end = performance.now();
respond(seq, undefined, { result, duration: end - start });

View file

@ -1,17 +1,16 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import { sql } from '../util';
import type { WritableDB } from '../Interface';
import { getOurUuid } from './41-uuid-keys';
export const version = 1020;
export function updateToSchemaVersion1020(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 1020) {

View file

@ -1,17 +1,14 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import { isValidUuid } from '../../util/isValidUuid';
import { assertSync } from '../../util/assert';
import Helpers from '../../textsecure/Helpers';
import { createOrUpdate, getById, removeById } from '../util';
import type { EmptyQuery, Query } from '../util';
import type { ItemKeyType } from '../Interface';
import type { ItemKeyType, ReadableDB, WritableDB } from '../Interface';
export function getOurUuid(db: Database): string | undefined {
export function getOurUuid(db: ReadableDB): string | undefined {
const UUID_ID: ItemKeyType = 'uuid_id';
const row: { json: string } | undefined = db
@ -30,7 +27,7 @@ export function getOurUuid(db: Database): string | undefined {
export default function updateToSchemaVersion41(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 41) {
@ -92,8 +89,8 @@ export default function updateToSchemaVersion41(
db.prepare('DELETE FROM preKeys').run().changes,
].reduce((a: number, b: number): number => a + b);
assertSync(removeById<string>(db, 'items', 'identityKey'));
assertSync(removeById<string>(db, 'items', 'registrationId'));
removeById<string>(db, 'items', 'identityKey');
removeById<string>(db, 'items', 'registrationId');
return keyCount;
};
@ -104,36 +101,34 @@ export default function updateToSchemaVersion41(
publicKey: string;
};
const identityKey = assertSync(
getById<string, { value: IdentityKeyType }>(db, 'items', 'identityKey')
const identityKey = getById<string, { value: IdentityKeyType }>(
db,
'items',
'identityKey'
);
type RegistrationId = number;
const registrationId = assertSync(
getById<string, { value: RegistrationId }>(db, 'items', 'registrationId')
const registrationId = getById<string, { value: RegistrationId }>(
db,
'items',
'registrationId'
);
if (identityKey) {
assertSync(
createOrUpdate<ItemKeyType>(db, 'items', {
id: 'identityKeyMap',
value: {
[ourUuid]: identityKey.value,
},
})
);
createOrUpdate<ItemKeyType>(db, 'items', {
id: 'identityKeyMap',
value: {
[ourUuid]: identityKey.value,
},
});
}
if (registrationId) {
assertSync(
createOrUpdate<ItemKeyType>(db, 'items', {
id: 'registrationIdMap',
value: {
[ourUuid]: registrationId.value,
},
})
);
createOrUpdate<ItemKeyType>(db, 'items', {
id: 'registrationIdMap',
value: {
[ourUuid]: registrationId.value,
},
});
}
db.exec(

View file

@ -1,15 +1,14 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import { batchMultiVarQuery } from '../util';
import type { ArrayQuery } from '../util';
import type { WritableDB } from '../Interface';
import type { LoggerType } from '../../types/Logging';
export default function updateToSchemaVersion42(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 42) {

View file

@ -1,7 +1,6 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import { omit } from 'lodash';
import type { LoggerType } from '../../types/Logging';
@ -16,6 +15,7 @@ import {
objectToJSON,
} from '../util';
import type { EmptyQuery, Query } from '../util';
import type { WritableDB } from '../Interface';
type MessageType = Readonly<{
id: string;
@ -35,7 +35,7 @@ type ConversationType = Readonly<{
export default function updateToSchemaVersion43(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 43) {

View file

@ -1,15 +1,14 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import { getOurUuid } from './41-uuid-keys';
import type { WritableDB } from '../Interface';
import type { Query } from '../util';
export default function updateToSchemaVersion47(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 47) {

View file

@ -1,19 +1,14 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import { isRecord } from '../../util/isRecord';
import {
getJobsInQueueSync,
getMessageByIdSync,
insertJobSync,
} from '../Server';
import type { WritableDB } from '../Interface';
import { getJobsInQueue, getMessageById, insertJob } from '../Server';
export default function updateToSchemaVersion51(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 51) {
@ -26,7 +21,7 @@ export default function updateToSchemaVersion51(
);
// First, make sure that reactions job data has a type and conversationId
const reactionsJobs = getJobsInQueueSync(db, 'reactions');
const reactionsJobs = getJobsInQueue(db, 'reactions');
deleteJobsInQueue.run({ queueType: 'reactions' });
reactionsJobs.forEach(job => {
@ -47,7 +42,7 @@ export default function updateToSchemaVersion51(
return;
}
const message = getMessageByIdSync(db, messageId);
const message = getMessageById(db, messageId);
if (!message) {
logger.warn(
`updateToSchemaVersion51: Unable to find message for reaction job ${id}`
@ -73,11 +68,11 @@ export default function updateToSchemaVersion51(
},
};
insertJobSync(db, newJob);
insertJob(db, newJob);
});
// Then make sure all normal send job data has a type
const normalSendJobs = getJobsInQueueSync(db, 'normal send');
const normalSendJobs = getJobsInQueue(db, 'normal send');
deleteJobsInQueue.run({ queueType: 'normal send' });
normalSendJobs.forEach(job => {
@ -99,7 +94,7 @@ export default function updateToSchemaVersion51(
},
};
insertJobSync(db, newJob);
insertJob(db, newJob);
});
db.pragma('user_version = 51');

View file

@ -1,15 +1,15 @@
// Copyright 2022 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import { getJobsInQueueSync, insertJobSync } from '../Server';
import { getJobsInQueue, insertJob } from '../Server';
import type { WritableDB } from '../Interface';
import { isRecord } from '../../util/isRecord';
import { isIterable } from '../../util/iterables';
export default function updateToSchemaVersion55(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 55) {
@ -22,7 +22,7 @@ export default function updateToSchemaVersion55(
);
// First, make sure that report spam job data has e164 and serverGuids
const reportSpamJobs = getJobsInQueueSync(db, 'report spam');
const reportSpamJobs = getJobsInQueue(db, 'report spam');
deleteJobsInQueue.run({ queueType: 'report spam' });
reportSpamJobs.forEach(job => {
@ -59,7 +59,7 @@ export default function updateToSchemaVersion55(
},
};
insertJobSync(db, newJob);
insertJob(db, newJob);
});
db.pragma('user_version = 55');

View file

@ -1,19 +1,14 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type { LoggerType } from '../../types/Logging';
import { isRecord } from '../../util/isRecord';
import {
getJobsInQueueSync,
getMessageByIdSync,
insertJobSync,
} from '../Server';
import type { WritableDB } from '../Interface';
import { getJobsInQueue, getMessageById, insertJob } from '../Server';
export default function updateToSchemaVersion78(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 78) {
@ -47,7 +42,7 @@ export default function updateToSchemaVersion78(
];
for (const queue of queues) {
const prevJobs = getJobsInQueueSync(db, queue.queueType);
const prevJobs = getJobsInQueue(db, queue.queueType);
deleteJobsInQueue.run({ queueType: queue.queueType });
prevJobs.forEach(job => {
@ -67,7 +62,7 @@ export default function updateToSchemaVersion78(
return;
}
const message = getMessageByIdSync(db, messageId);
const message = getMessageById(db, messageId);
if (!message) {
logger.warn(
`updateToSchemaVersion78: Unable to find message for ${queue.queueType} job ${id}`
@ -121,7 +116,7 @@ export default function updateToSchemaVersion78(
},
};
insertJobSync(db, newJob);
insertJob(db, newJob);
});
}

View file

@ -1,7 +1,6 @@
// Copyright 2023 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import { callIdFromEra } from '@signalapp/ringrtc';
import Long from 'long';
import { v4 as generateUuid } from 'uuid';
@ -20,7 +19,7 @@ import {
callHistoryDetailsSchema,
} from '../../types/CallDisposition';
import { CallMode } from '../../types/Calling';
import type { MessageType, ConversationType } from '../Interface';
import type { WritableDB, MessageType, ConversationType } from '../Interface';
import { strictAssert } from '../../util/assert';
import { missingCaseError } from '../../util/missingCaseError';
import { isAciString } from '../../util/isAciString';
@ -188,7 +187,7 @@ function convertLegacyCallDetails(
export default function updateToSchemaVersion89(
currentVersion: number,
db: Database,
db: WritableDB,
logger: LoggerType
): void {
if (currentVersion >= 89) {

View file

@ -15,6 +15,7 @@ import {
jsonToObject,
} from '../util';
import type { Query, EmptyQuery } from '../util';
import type { WritableDB } from '../Interface';
import updateToSchemaVersion41 from './41-uuid-keys';
import updateToSchemaVersion42 from './42-stale-reactions';
@ -2075,7 +2076,7 @@ export function enableFTS5SecureDelete(db: Database, logger: LoggerType): void {
}
}
export function updateSchema(db: Database, logger: LoggerType): void {
export function updateSchema(db: WritableDB, logger: LoggerType): void {
const sqliteVersion = getSQLiteVersion(db);
const sqlcipherVersion = getSQLCipherVersion(db);
const startingVersion = getUserVersion(db);

View file

@ -1,7 +1,6 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import { CallLinkRootKey } from '@signalapp/ringrtc';
import type { CallLinkStateType, CallLinkType } from '../../types/CallLink';
import {
@ -13,12 +12,12 @@ import {
callLinkFromRecord,
toAdminKeyBytes,
} from '../../util/callLinks';
import { getReadonlyInstance, getWritableInstance, prepare } from '../Server';
import type { ReadableDB, WritableDB } from '../Interface';
import { prepare } from '../Server';
import { sql } from '../util';
import { strictAssert } from '../../util/assert';
export async function callLinkExists(roomId: string): Promise<boolean> {
const db = getReadonlyInstance();
export function callLinkExists(db: ReadableDB, roomId: string): boolean {
const [query, params] = sql`
SELECT 1
FROM callLinks
@ -27,10 +26,10 @@ export async function callLinkExists(roomId: string): Promise<boolean> {
return db.prepare(query).pluck(true).get(params) === 1;
}
export async function getCallLinkByRoomId(
export function getCallLinkByRoomId(
db: ReadableDB,
roomId: string
): Promise<CallLinkType | undefined> {
const db = getReadonlyInstance();
): CallLinkType | undefined {
const row = prepare(db, 'SELECT * FROM callLinks WHERE roomId = $roomId').get(
{
roomId,
@ -44,8 +43,7 @@ export async function getCallLinkByRoomId(
return callLinkFromRecord(callLinkRecordSchema.parse(row));
}
export async function getAllCallLinks(): Promise<ReadonlyArray<CallLinkType>> {
const db = getReadonlyInstance();
export function getAllCallLinks(db: ReadableDB): ReadonlyArray<CallLinkType> {
const [query] = sql`
SELECT * FROM callLinks;
`;
@ -55,7 +53,7 @@ export async function getAllCallLinks(): Promise<ReadonlyArray<CallLinkType>> {
.map(item => callLinkFromRecord(callLinkRecordSchema.parse(item)));
}
function _insertCallLink(db: Database, callLink: CallLinkType): void {
function _insertCallLink(db: WritableDB, callLink: CallLinkType): void {
const { roomId, rootKey } = callLink;
assertRoomIdMatchesRootKey(roomId, rootKey);
@ -84,17 +82,16 @@ function _insertCallLink(db: Database, callLink: CallLinkType): void {
).run(data);
}
export async function insertCallLink(callLink: CallLinkType): Promise<void> {
const db = await getWritableInstance();
export function insertCallLink(db: WritableDB, callLink: CallLinkType): void {
_insertCallLink(db, callLink);
}
export async function updateCallLinkState(
export function updateCallLinkState(
db: WritableDB,
roomId: string,
callLinkState: CallLinkStateType
): Promise<CallLinkType> {
): CallLinkType {
const { name, restrictions, expiration, revoked } = callLinkState;
const db = await getWritableInstance();
const restrictionsValue = callLinkRestrictionsSchema.parse(restrictions);
const [query, params] = sql`
UPDATE callLinks
@ -111,11 +108,11 @@ export async function updateCallLinkState(
return callLinkFromRecord(callLinkRecordSchema.parse(row));
}
export async function updateCallLinkAdminKeyByRoomId(
export function updateCallLinkAdminKeyByRoomId(
db: WritableDB,
roomId: string,
adminKey: string
): Promise<void> {
const db = await getWritableInstance();
): void {
const adminKeyBytes = toAdminKeyBytes(adminKey);
prepare(
db,

View file

@ -1,23 +1,23 @@
// Copyright 2024 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import type {
GroupSendCombinedEndorsementRecord,
GroupSendEndorsementsData,
GroupSendMemberEndorsementRecord,
} from '../../types/GroupSendEndorsements';
import { groupSendEndorsementExpirationSchema } from '../../types/GroupSendEndorsements';
import { getReadonlyInstance, getWritableInstance, prepare } from '../Server';
import { prepare } from '../Server';
import type { ReadableDB, WritableDB } from '../Interface';
import { sql } from '../util';
/**
* We don't need to store more than one endorsement per group or per member.
*/
export async function replaceAllEndorsementsForGroup(
export function replaceAllEndorsementsForGroup(
db: WritableDB,
data: GroupSendEndorsementsData
): Promise<void> {
const db = await getWritableInstance();
): void {
db.transaction(() => {
const { combinedEndorsement, memberEndorsements } = data;
_replaceCombinedEndorsement(db, combinedEndorsement);
@ -26,7 +26,7 @@ export async function replaceAllEndorsementsForGroup(
}
function _replaceCombinedEndorsement(
db: Database,
db: WritableDB,
combinedEndorsement: GroupSendCombinedEndorsementRecord
): void {
const { groupId, expiration, endorsement } = combinedEndorsement;
@ -39,7 +39,7 @@ function _replaceCombinedEndorsement(
}
function _replaceMemberEndorsements(
db: Database,
db: WritableDB,
memberEndorsements: ReadonlyArray<GroupSendMemberEndorsementRecord>
) {
for (const memberEndorsement of memberEndorsements) {
@ -53,10 +53,10 @@ function _replaceMemberEndorsements(
}
}
export async function deleteAllEndorsementsForGroup(
export function deleteAllEndorsementsForGroup(
db: WritableDB,
groupId: string
): Promise<void> {
const db = await getWritableInstance();
): void {
db.transaction(() => {
const [deleteCombined, deleteCombinedParams] = sql`
DELETE FROM groupSendCombinedEndorsement
@ -71,10 +71,10 @@ export async function deleteAllEndorsementsForGroup(
})();
}
export async function getGroupSendCombinedEndorsementExpiration(
export function getGroupSendCombinedEndorsementExpiration(
db: ReadableDB,
groupId: string
): Promise<number | null> {
const db = getReadonlyInstance();
): number | null {
const [selectGroup, selectGroupParams] = sql`
SELECT expiration FROM groupSendCombinedEndorsement
WHERE groupId = ${groupId};

View file

@ -1,8 +1,8 @@
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
import type { Database } from '@signalapp/better-sqlite3';
import { isNumber, last } from 'lodash';
import type { ReadableDB, WritableDB } from './Interface';
export type EmptyQuery = [];
export type ArrayQuery = Array<ReadonlyArray<null | number | bigint | string>>;
@ -185,7 +185,7 @@ type QueryPlan = Readonly<{
* ```
*/
export function explainQueryPlan(
db: Database,
db: ReadableDB,
template: QueryTemplate
): QueryPlan {
const [query, params] = template;
@ -197,7 +197,7 @@ export function explainQueryPlan(
// Database helpers
//
export function getSQLiteVersion(db: Database): string {
export function getSQLiteVersion(db: ReadableDB): string {
const { sqlite_version: version } = db
.prepare<EmptyQuery>('select sqlite_version() AS sqlite_version')
.get();
@ -205,22 +205,22 @@ export function getSQLiteVersion(db: Database): string {
return version;
}
export function getSchemaVersion(db: Database): number {
export function getSchemaVersion(db: ReadableDB): number {
return db.pragma('schema_version', { simple: true });
}
export function setUserVersion(db: Database, version: number): void {
export function setUserVersion(db: WritableDB, version: number): void {
if (!isNumber(version)) {
throw new Error(`setUserVersion: version ${version} is not a number`);
}
db.pragma(`user_version = ${version}`);
}
export function getUserVersion(db: Database): number {
export function getUserVersion(db: ReadableDB): number {
return db.pragma('user_version', { simple: true });
}
export function getSQLCipherVersion(db: Database): string | undefined {
export function getSQLCipherVersion(db: ReadableDB): string | undefined {
return db.pragma('cipher_version', { simple: true });
}
@ -229,18 +229,18 @@ export function getSQLCipherVersion(db: Database): string | undefined {
//
export function batchMultiVarQuery<ValueT>(
db: Database,
db: ReadableDB,
values: ReadonlyArray<ValueT>,
query: (batch: ReadonlyArray<ValueT>) => void
): [];
export function batchMultiVarQuery<ValueT, ResultT>(
db: Database,
db: ReadableDB,
values: ReadonlyArray<ValueT>,
query: (batch: ReadonlyArray<ValueT>) => Array<ResultT>
): Array<ResultT>;
export function batchMultiVarQuery<ValueT, ResultT>(
db: Database,
db: ReadableDB,
values: ReadonlyArray<ValueT>,
query:
| ((batch: ReadonlyArray<ValueT>) => void)
@ -265,7 +265,7 @@ export function batchMultiVarQuery<ValueT, ResultT>(
}
export function createOrUpdate<Key extends string | number>(
db: Database,
db: WritableDB,
table: TableType,
data: Record<string, unknown> & { id: Key }
): void {
@ -291,7 +291,7 @@ export function createOrUpdate<Key extends string | number>(
}
export function bulkAdd(
db: Database,
db: WritableDB,
table: TableType,
array: Array<Record<string, unknown> & { id: string | number }>
): void {
@ -303,7 +303,7 @@ export function bulkAdd(
}
export function getById<Key extends string | number, Result = unknown>(
db: Database,
db: ReadableDB,
table: TableType,
id: Key
): Result | undefined {
@ -327,7 +327,7 @@ export function getById<Key extends string | number, Result = unknown>(
}
export function removeById<Key extends string | number>(
db: Database,
db: WritableDB,
tableName: TableType,
id: Key | Array<Key>
): number {
@ -359,11 +359,11 @@ export function removeById<Key extends string | number>(
return totalChanges;
}
export function removeAllFromTable(db: Database, table: TableType): number {
export function removeAllFromTable(db: WritableDB, table: TableType): number {
return db.prepare<EmptyQuery>(`DELETE FROM ${table};`).run().changes;
}
export function getAllFromTable<T>(db: Database, table: TableType): Array<T> {
export function getAllFromTable<T>(db: ReadableDB, table: TableType): Array<T> {
const rows: JSONRows = db
.prepare<EmptyQuery>(`SELECT json FROM ${table};`)
.all();
@ -371,7 +371,7 @@ export function getAllFromTable<T>(db: Database, table: TableType): Array<T> {
return rows.map(row => jsonToObject(row.json));
}
export function getCountFromTable(db: Database, table: TableType): number {
export function getCountFromTable(db: ReadableDB, table: TableType): number {
const result: null | number = db
.prepare<EmptyQuery>(`SELECT count(*) from ${table};`)
.pluck(true)
@ -384,7 +384,7 @@ export function getCountFromTable(db: Database, table: TableType): number {
export class TableIterator<ObjectType extends { id: string }> {
constructor(
private readonly db: Database,
private readonly db: ReadableDB,
private readonly table: TableType,
private readonly pageSize = 500
) {}

View file

@ -4,6 +4,7 @@
import type { ThunkAction } from 'redux-thunk';
import { isEqual, mapValues } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import { DataWriter } from '../../sql/Client';
import type { StateType as RootStateType } from '../reducer';
import type { BadgeType, BadgeImageType } from '../../badges/types';
import { getOwn } from '../../util/getOwn';
@ -70,7 +71,7 @@ function updateOrCreate(
// check (e.g., due to a crash), we won't download its image files. In the unlikely
// event that this happens, we'll repair it the next time we check for undownloaded
// image files.
await window.Signal.Data.updateOrCreateBadges(badges);
await DataWriter.updateOrCreateBadges(badges);
dispatch({
type: UPDATE_OR_CREATE,

View file

@ -13,6 +13,7 @@ import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions';
import type { ToastActionType } from './toast';
import { showToast } from './toast';
import { DataReader, DataWriter } from '../../sql/Client';
import { ToastType } from '../../types/Toast';
import type { CallHistoryDetails } from '../../types/CallDisposition';
import * as log from '../../logging/log';
@ -77,7 +78,7 @@ function updateCallHistoryUnreadCount(): ThunkAction<
> {
return async dispatch => {
try {
const unreadCount = await window.Signal.Data.getCallHistoryUnreadCount();
const unreadCount = await DataReader.getCallHistoryUnreadCount();
dispatch({ type: CALL_HISTORY_UPDATE_UNREAD, payload: unreadCount });
} catch (error) {
log.error(
@ -94,7 +95,7 @@ function markCallHistoryRead(
): ThunkAction<void, RootStateType, unknown, CallHistoryUpdateUnread> {
return async dispatch => {
try {
await window.Signal.Data.markCallHistoryRead(callId);
await DataWriter.markCallHistoryRead(callId);
drop(window.ConversationController.get(conversationId)?.updateUnread());
} catch (error) {
log.error(

View file

@ -86,7 +86,7 @@ import type { ShowErrorModalActionType } from './globalModals';
import { SHOW_ERROR_MODAL } from './globalModals';
import { ButtonVariant } from '../../components/Button';
import { getConversationIdForLogging } from '../../util/idForLogging';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { isAciString } from '../../util/isAciString';
import type { CallHistoryDetails } from '../../types/CallDisposition';
import {
@ -1415,7 +1415,7 @@ function handleCallLinkUpdate(
}
const { callLinkState: freshCallLinkState } = readResult;
const existingCallLink = await dataInterface.getCallLinkByRoomId(roomId);
const existingCallLink = await DataReader.getCallLinkByRoomId(roomId);
const existingCallLinkState = pick(existingCallLink, [
'name',
'restrictions',
@ -1434,16 +1434,16 @@ function handleCallLinkUpdate(
if (existingCallLink) {
if (adminKey && adminKey !== existingCallLink.adminKey) {
await dataInterface.updateCallLinkAdminKeyByRoomId(roomId, adminKey);
await DataWriter.updateCallLinkAdminKeyByRoomId(roomId, adminKey);
log.info(`${logId}: Updated existing call link with new adminKey`);
}
if (freshCallLinkState) {
await dataInterface.updateCallLinkState(roomId, freshCallLinkState);
await DataWriter.updateCallLinkState(roomId, freshCallLinkState);
log.info(`${logId}: Updated existing call link state`);
}
} else {
await dataInterface.insertCallLink(callLink);
await DataWriter.insertCallLink(callLink);
log.info(`${logId}: Saved new call link`);
}
@ -1985,8 +1985,8 @@ function createCallLink(
status: AdhocCallStatus.Pending,
};
await Promise.all([
dataInterface.insertCallLink(callLink),
dataInterface.saveCallHistory(callHistory),
DataWriter.insertCallLink(callLink),
DataWriter.saveCallHistory(callHistory),
]);
dispatch({
type: HANDLE_CALL_LINK_UPDATE,
@ -2003,13 +2003,13 @@ function updateCallLinkName(
name: string
): ThunkAction<void, RootStateType, unknown, HandleCallLinkUpdateActionType> {
return async dispatch => {
const prevCallLink = await dataInterface.getCallLinkByRoomId(roomId);
const prevCallLink = await DataReader.getCallLinkByRoomId(roomId);
strictAssert(
prevCallLink,
`updateCallLinkName(${roomId}): call link not found`
);
const callLinkState = await calling.updateCallLinkName(prevCallLink, name);
const callLink = await dataInterface.updateCallLinkState(
const callLink = await DataWriter.updateCallLinkState(
roomId,
callLinkState
);
@ -2025,7 +2025,7 @@ function updateCallLinkRestrictions(
restrictions: CallLinkRestrictions
): ThunkAction<void, RootStateType, unknown, HandleCallLinkUpdateActionType> {
return async dispatch => {
const prevCallLink = await dataInterface.getCallLinkByRoomId(roomId);
const prevCallLink = await DataReader.getCallLinkByRoomId(roomId);
strictAssert(
prevCallLink,
`updateCallLinkRestrictions(${roomId}): call link not found`
@ -2034,7 +2034,7 @@ function updateCallLinkRestrictions(
prevCallLink,
restrictions
);
const callLink = await dataInterface.updateCallLinkState(
const callLink = await DataWriter.updateCallLinkState(
roomId,
callLinkState
);
@ -2126,13 +2126,13 @@ const _startCallLinkLobby = async ({
}
try {
const callLinkExists = await dataInterface.callLinkExists(roomId);
const callLinkExists = await DataReader.callLinkExists(roomId);
if (callLinkExists) {
await dataInterface.updateCallLinkState(roomId, callLinkState);
await DataWriter.updateCallLinkState(roomId, callLinkState);
log.info('startCallLinkLobby: Updated existing call link', roomId);
} else {
const { name, restrictions, expiration, revoked } = callLinkState;
await dataInterface.insertCallLink({
await DataWriter.insertCallLink({
roomId,
rootKey,
adminKey: null,

View file

@ -18,6 +18,7 @@ import {
isVideoAttachment,
isImageAttachment,
} from '../../types/Attachment';
import { DataReader, DataWriter } from '../../sql/Client';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import type { DraftBodyRanges } from '../../types/BodyRange';
import type { LinkPreviewType } from '../../types/message/LinkPreviews';
@ -336,7 +337,7 @@ function scrollToQuotedMessage({
ShowToastActionType | ScrollToMessageActionType
> {
return async (dispatch, getState) => {
const messages = await window.Signal.Data.getMessagesBySentAt(sentAt);
const messages = await DataReader.getMessagesBySentAt(sentAt);
const message = messages.find(item =>
Boolean(
item.conversationId === conversationId &&
@ -765,7 +766,7 @@ export function setQuoteByMessageId(
timestamp,
});
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
}
if (message) {
@ -866,7 +867,7 @@ function addAttachment(
});
}
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
}
};
}
@ -904,7 +905,7 @@ function addPendingAttachment(
if (conversation) {
conversation.attributes.draftAttachments = nextAttachments;
conversation.attributes.draftChanged = true;
window.Signal.Data.updateConversation(conversation.attributes);
drop(DataWriter.updateConversation(conversation.attributes));
}
};
}
@ -1201,7 +1202,7 @@ function removeAttachment(
if (conversation) {
conversation.attributes.draftAttachments = nextAttachments;
conversation.attributes.draftChanged = true;
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
}
replaceAttachments(conversationId, nextAttachments)(
@ -1312,7 +1313,7 @@ function saveDraft(
draftChanged: true,
draftBodyRanges: [],
});
window.Signal.Data.updateConversation(conversation.attributes);
drop(DataWriter.updateConversation(conversation.attributes));
return;
}
@ -1336,7 +1337,7 @@ function saveDraft(
draftChanged: true,
timestamp,
});
window.Signal.Data.updateConversation(conversation.attributes);
drop(DataWriter.updateConversation(conversation.attributes));
}
}

View file

@ -17,6 +17,7 @@ import type { PhoneNumber } from 'google-libphonenumber';
import { clipboard } from 'electron';
import type { ReadonlyDeep } from 'type-fest';
import { DataReader, DataWriter } from '../../sql/Client';
import type { AttachmentType } from '../../types/Attachment';
import type { StateType as RootStateType } from '../reducer';
import * as groups from '../../groups';
@ -1480,7 +1481,7 @@ async function getAvatarsAndUpdateConversation(
conversation.attributes.avatars = nextAvatars.map(avatarData =>
omit(avatarData, ['buffer'])
);
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
return nextAvatars;
}
@ -1750,21 +1751,20 @@ function deleteMessages({
let nearbyMessageId: string | null = null;
if (nearbyMessageId == null && lastSelectedMessage != null) {
const foundMessageId =
await window.Signal.Data.getNearbyMessageFromDeletedSet({
conversationId,
lastSelectedMessage,
deletedMessageIds: messageIds,
includeStoryReplies: false,
storyId: undefined,
});
const foundMessageId = await DataReader.getNearbyMessageFromDeletedSet({
conversationId,
lastSelectedMessage,
deletedMessageIds: messageIds,
includeStoryReplies: false,
storyId: undefined,
});
if (foundMessageId != null) {
nearbyMessageId = foundMessageId;
}
}
await window.Signal.Data.removeMessages(messageIds, {
await DataWriter.removeMessages(messageIds, {
singleProtoJobQueue,
});
@ -2189,7 +2189,7 @@ function removeCustomColorOnConversations(
});
if (conversationsToUpdate.length) {
await window.Signal.Data.updateConversations(conversationsToUpdate);
await DataWriter.updateConversations(conversationsToUpdate);
}
dispatch({
@ -2209,7 +2209,7 @@ function resetAllChatColors(): ThunkAction<
> {
return async dispatch => {
// Calling this with no args unsets all the colors in the db
await window.Signal.Data.updateAllConversationColors();
await DataWriter.updateAllConversationColors();
window.getConversations().forEach(conversation => {
conversation.set({
@ -2245,7 +2245,7 @@ function kickOffAttachmentDownload(
if (didUpdateValues) {
drop(
window.Signal.Data.saveMessage(message.attributes, {
DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
})
);
@ -2402,7 +2402,7 @@ export function setVoiceNotePlaybackRate({
conversationModel.set({
voiceNotePlaybackRate: rate === 1 ? undefined : rate,
});
window.Signal.Data.updateConversation(conversationModel.attributes);
await DataWriter.updateConversation(conversationModel.attributes);
}
const conversation = conversationModel?.format();
@ -2456,7 +2456,7 @@ function colorSelected({
});
}
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
}
dispatch({
@ -2779,20 +2779,17 @@ function toggleSelectMessage(
message => message
);
const betweenIds = await window.Signal.Data.getMessagesBetween(
conversationId,
{
after: {
sent_at: after.sent_at,
received_at: after.received_at,
},
before: {
sent_at: before.sent_at,
received_at: before.received_at,
},
includeStoryReplies: !isGroup(conversation.attributes),
}
);
const betweenIds = await DataReader.getMessagesBetween(conversationId, {
after: {
sent_at: after.sent_at,
received_at: after.received_at,
},
before: {
sent_at: before.sent_at,
received_at: before.received_at,
},
includeStoryReplies: !isGroup(conversation.attributes),
});
toggledMessageIds = [messageId, ...betweenIds];
} else {
@ -3434,7 +3431,7 @@ function reportSpam(
addReportSpamJob({
conversation,
getMessageServerGuidsForSpam:
window.Signal.Data.getMessageServerGuidsForSpam,
DataReader.getMessageServerGuidsForSpam,
jobQueue: reportSpamJobQueue,
}),
]);
@ -3484,7 +3481,7 @@ function blockAndReportSpam(
addReportSpamJob({
conversation: conversationForSpam,
getMessageServerGuidsForSpam:
window.Signal.Data.getMessageServerGuidsForSpam,
DataReader.getMessageServerGuidsForSpam,
jobQueue: reportSpamJobQueue,
}),
]);
@ -3654,12 +3651,9 @@ function loadRecentMediaItems(
): ThunkAction<void, RootStateType, unknown, SetRecentMediaItemsActionType> {
return async dispatch => {
const messages: Array<MessageAttributesType> =
await window.Signal.Data.getMessagesWithVisualMediaAttachments(
conversationId,
{
limit,
}
);
await DataReader.getMessagesWithVisualMediaAttachments(conversationId, {
limit,
});
// Cache these messages in memory to ensure Lightbox can find them
messages.forEach(message => {
@ -3839,7 +3833,7 @@ export function scrollToOldestUnreadMention(
}
const oldestUnreadMention =
await window.Signal.Data.getOldestUnreadMentionOfMeForConversation(
await DataReader.getOldestUnreadMentionOfMeForConversation(
conversationId,
{
includeStoryReplies: !isGroup(conversation),
@ -4151,7 +4145,7 @@ function toggleGroupsForStorySend(
conversation.set({
storySendMode: newStorySendMode,
});
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
conversation.captureChange('storySendMode');
})
);
@ -4413,7 +4407,7 @@ function onConversationClosed(
});
}
window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
drop(conversation.updateLastMessage());
}
@ -4784,7 +4778,7 @@ function updateNicknameAndNote(
nicknameFamilyName: nickname?.familyName,
note,
});
window.Signal.Data.updateConversation(conversationModel.attributes);
await DataWriter.updateConversation(conversationModel.attributes);
const conversation = conversationModel.format();
dispatch(conversationChanged(conversationId, conversation));
conversationModel.captureChange('nicknameAndNote');

View file

@ -5,11 +5,11 @@ import { take, uniq } from 'lodash';
import type { ThunkAction } from 'redux-thunk';
import type { ReadonlyDeep } from 'type-fest';
import type { EmojiPickDataType } from '../../components/emoji/EmojiPicker';
import dataInterface from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions';
const { updateEmojiUsage } = dataInterface;
const { updateEmojiUsage } = DataWriter;
// State

View file

@ -39,7 +39,7 @@ import {
} from './conversations';
import { showStickerPackPreview } from './globalModals';
import { useBoundActions } from '../../hooks/useBoundActions';
import dataInterface from '../../sql/Client';
import { DataReader } from '../../sql/Client';
// eslint-disable-next-line local-rules/type-alias-readonlydeep
export type LightboxStateType =
@ -349,7 +349,7 @@ function showLightbox(opts: {
}
const { older, newer } =
await dataInterface.getConversationRangeCenteredOnMessage({
await DataReader.getConversationRangeCenteredOnMessage({
conversationId: message.get('conversationId'),
messageId,
receivedAt,
@ -436,8 +436,8 @@ function showLightboxForAdjacentMessage(
const [adjacent] =
direction === AdjacentMessageDirection.Previous
? await dataInterface.getOlderMessagesByConversation(options)
: await dataInterface.getNewerMessagesByConversation(options);
? await DataReader.getOlderMessagesByConversation(options)
: await DataReader.getNewerMessagesByConversation(options);
if (!adjacent) {
log.warn(

View file

@ -15,7 +15,7 @@ import type { MIMEType } from '../../types/MIME';
import type { MediaItemType } from '../../types/MediaItem';
import type { StateType as RootStateType } from '../reducer';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import {
CONVERSATION_UNLOADED,
MESSAGE_CHANGED,
@ -84,13 +84,13 @@ function loadMediaItems(
const ourAci = window.textsecure.storage.user.getCheckedAci();
const rawMedia = await dataInterface.getMessagesWithVisualMediaAttachments(
const rawMedia = await DataReader.getMessagesWithVisualMediaAttachments(
conversationId,
{
limit: DEFAULT_MEDIA_FETCH_COUNT,
}
);
const rawDocuments = await dataInterface.getMessagesWithFileAttachments(
const rawDocuments = await DataReader.getMessagesWithFileAttachments(
conversationId,
{
limit: DEFAULT_DOCUMENTS_FETCH_COUNT,
@ -111,7 +111,7 @@ function loadMediaItems(
const upgradedMsgAttributes = await upgradeMessageSchema(message);
model.set(upgradedMsgAttributes);
await dataInterface.saveMessage(upgradedMsgAttributes, { ourAci });
await DataWriter.saveMessage(upgradedMsgAttributes, { ourAci });
}
})
);

View file

@ -7,11 +7,8 @@ import { debounce, omit, reject } from 'lodash';
import type { ReadonlyDeep } from 'type-fest';
import type { StateType as RootStateType } from '../reducer';
import { filterAndSortConversations } from '../../util/filterAndSortConversations';
import type {
ClientSearchResultMessageType,
ClientInterface,
} from '../../sql/Interface';
import dataInterface from '../../sql/Client';
import type { ClientSearchResultMessageType } from '../../sql/Interface';
import { DataReader } from '../../sql/Client';
import { makeLookup } from '../../util/makeLookup';
import { isNotNil } from '../../util/isNotNil';
import type { ServiceIdString } from '../../types/ServiceId';
@ -44,7 +41,7 @@ import * as log from '../../logging/log';
import { searchConversationTitles } from '../../util/searchConversationTitles';
import { isDirectConversation } from '../../util/whatTypeOfConversation';
const { searchMessages: dataSearchMessages }: ClientInterface = dataInterface;
const { searchMessages: dataSearchMessages } = DataReader;
// State

View file

@ -9,7 +9,7 @@ import type {
StickerType as StickerDBType,
StickerPackType as StickerPackDBType,
} from '../../sql/Interface';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import type { RecentStickerType } from '../../types/Stickers';
import {
downloadStickerPack as externalDownloadStickerPack,
@ -25,7 +25,8 @@ import type { NoopActionType } from './noop';
import type { BoundActionCreatorsMapObject } from '../../hooks/useBoundActions';
import { useBoundActions } from '../../hooks/useBoundActions';
const { getRecentStickers, updateStickerLastUsed } = dataInterface;
const { getRecentStickers } = DataReader;
const { updateStickerLastUsed } = DataWriter;
// State
@ -241,7 +242,7 @@ async function doInstallStickerPack(
} = options;
const timestamp = Date.now();
await dataInterface.installStickerPack(packId, timestamp);
await DataWriter.installStickerPack(packId, timestamp);
if (!fromSync && !fromStorageService && !fromBackup) {
// Kick this off, but don't wait for it
@ -283,7 +284,7 @@ async function doUninstallStickerPack(
const { fromSync = false, fromStorageService = false } = options;
const timestamp = Date.now();
await dataInterface.uninstallStickerPack(packId, timestamp);
await DataWriter.uninstallStickerPack(packId, timestamp);
// If there are no more references, it should be removed
await maybeDeletePack(packId);

View file

@ -25,7 +25,7 @@ import { isAciString } from '../../util/isAciString';
import * as log from '../../logging/log';
import { TARGETED_CONVERSATION_CHANGED } from './conversations';
import { SIGNAL_ACI } from '../../types/SignalConversation';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { ReadStatus } from '../../messages/MessageReadStatus';
import { SendStatus } from '../../messages/MessageSendState';
import { SafetyNumberChangeSource } from '../../components/SafetyNumberChangeDialog';
@ -285,7 +285,7 @@ function deleteGroupStoryReply(
messageId: string
): ThunkAction<void, RootStateType, unknown, StoryReplyDeletedActionType> {
return async dispatch => {
await window.Signal.Data.removeMessage(messageId, { singleProtoJobQueue });
await DataWriter.removeMessage(messageId, { singleProtoJobQueue });
dispatch({
type: STORY_REPLY_DELETED,
payload: messageId,
@ -337,7 +337,7 @@ function loadStoryReplies(
): ThunkAction<void, RootStateType, unknown, LoadStoryRepliesActionType> {
return async (dispatch, getState) => {
const conversation = getConversationSelector(getState())(conversationId);
const replies = await dataInterface.getOlderMessagesByConversation({
const replies = await DataReader.getOlderMessagesByConversation({
conversationId,
limit: 9000,
storyId: messageId,
@ -421,7 +421,7 @@ function markStoryRead(
message.set(markViewed(message.attributes, storyReadDate));
drop(
dataInterface.saveMessage(message.attributes, {
DataWriter.saveMessage(message.attributes, {
ourAci: window.textsecure.storage.user.getCheckedAci(),
})
);
@ -459,7 +459,7 @@ function markStoryRead(
);
}
await dataInterface.addNewStoryRead({
await DataWriter.addNewStoryRead({
authorId,
conversationId: message.attributes.conversationId,
storyId: messageId,
@ -1409,7 +1409,7 @@ function removeAllContactStories(
log.info(`${logId}: removing ${messages.length} stories`);
await dataInterface.removeMessages(messageIds, { singleProtoJobQueue });
await DataWriter.removeMessages(messageIds, { singleProtoJobQueue });
dispatch({
type: 'NOOP',

View file

@ -10,7 +10,7 @@ import type { StoryDistributionWithMembersType } from '../../sql/Interface';
import type { StoryDistributionIdString } from '../../types/StoryDistributionId';
import type { ServiceIdString } from '../../types/ServiceId';
import * as log from '../../logging/log';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { MY_STORY_ID } from '../../types/Stories';
import { generateStoryDistributionId } from '../../types/StoryDistributionId';
import { deleteStoryForEveryone } from '../../util/deleteStoryForEveryone';
@ -112,8 +112,9 @@ function allowsRepliesChanged(
allowsReplies: boolean
): ThunkAction<void, RootStateType, null, AllowRepliesChangedActionType> {
return async dispatch => {
const storyDistribution =
await dataInterface.getStoryDistributionWithMembers(listId);
const storyDistribution = await DataReader.getStoryDistributionWithMembers(
listId
);
if (!storyDistribution) {
log.warn(
@ -131,7 +132,7 @@ function allowsRepliesChanged(
return;
}
await dataInterface.modifyStoryDistribution({
await DataWriter.modifyStoryDistribution({
...storyDistribution,
allowsReplies,
storageNeedsSync: true,
@ -178,7 +179,7 @@ function createDistributionList(
};
if (shouldSave) {
await dataInterface.createNewStoryDistribution(storyDistribution);
await DataWriter.createNewStoryDistribution(storyDistribution);
}
if (storyDistribution.storageNeedsSync) {
@ -207,15 +208,16 @@ function deleteDistributionList(
return async (dispatch, getState) => {
const deletedAtTimestamp = Date.now();
const storyDistribution =
await dataInterface.getStoryDistributionWithMembers(listId);
const storyDistribution = await DataReader.getStoryDistributionWithMembers(
listId
);
if (!storyDistribution) {
log.warn('No story distribution found for id', listId);
return;
}
await dataInterface.modifyStoryDistributionWithMembers(
await DataWriter.modifyStoryDistributionWithMembers(
{
...storyDistribution,
deletedAtTimestamp,
@ -266,7 +268,7 @@ function hideMyStoriesFrom(
memberServiceIds: Array<ServiceIdString>
): ThunkAction<void, RootStateType, null, HideMyStoriesFromActionType> {
return async dispatch => {
const myStories = await dataInterface.getStoryDistributionWithMembers(
const myStories = await DataReader.getStoryDistributionWithMembers(
MY_STORY_ID
);
@ -279,7 +281,7 @@ function hideMyStoriesFrom(
const toAdd = new Set<ServiceIdString>(memberServiceIds);
await dataInterface.modifyStoryDistributionWithMembers(
await DataWriter.modifyStoryDistributionWithMembers(
{
...myStories,
isBlockList: true,
@ -315,8 +317,9 @@ function removeMembersFromDistributionList(
return;
}
const storyDistribution =
await dataInterface.getStoryDistributionWithMembers(listId);
const storyDistribution = await DataReader.getStoryDistributionWithMembers(
listId
);
if (!storyDistribution) {
log.warn(
@ -343,7 +346,7 @@ function removeMembersFromDistributionList(
await window.storage.put('hasSetMyStoriesPrivacy', true);
}
await dataInterface.modifyStoryDistributionWithMembers(
await DataWriter.modifyStoryDistributionWithMembers(
{
...storyDistribution,
isBlockList,
@ -385,7 +388,7 @@ function setMyStoriesToAllSignalConnections(): ThunkAction<
ResetMyStoriesActionType
> {
return async dispatch => {
const myStories = await dataInterface.getStoryDistributionWithMembers(
const myStories = await DataReader.getStoryDistributionWithMembers(
MY_STORY_ID
);
@ -397,7 +400,7 @@ function setMyStoriesToAllSignalConnections(): ThunkAction<
}
if (myStories.isBlockList || myStories.members.length > 0) {
await dataInterface.modifyStoryDistributionWithMembers(
await DataWriter.modifyStoryDistributionWithMembers(
{
...myStories,
isBlockList: true,
@ -425,8 +428,9 @@ function updateStoryViewers(
memberServiceIds: Array<ServiceIdString>
): ThunkAction<void, RootStateType, null, ViewersChangedActionType> {
return async dispatch => {
const storyDistribution =
await dataInterface.getStoryDistributionWithMembers(listId);
const storyDistribution = await DataReader.getStoryDistributionWithMembers(
listId
);
if (!storyDistribution) {
log.warn(
@ -456,7 +460,7 @@ function updateStoryViewers(
}
});
await dataInterface.modifyStoryDistributionWithMembers(
await DataWriter.modifyStoryDistributionWithMembers(
{
...storyDistribution,
isBlockList: false,
@ -489,7 +493,7 @@ function removeMemberFromAllDistributionLists(
): ThunkAction<void, RootStateType, null, ModifyListActionType> {
return async dispatch => {
const logId = `removeMemberFromAllDistributionLists(${member})`;
const lists = await dataInterface.getAllStoryDistributionsWithMembers();
const lists = await DataReader.getAllStoryDistributionsWithMembers();
const listsWithMember = lists.filter(({ members }) =>
members.includes(member)

View file

@ -3,6 +3,7 @@
import React, { memo } from 'react';
import { useSelector } from 'react-redux';
import type { VerificationTransport } from '../../types/VerificationTransport';
import { DataWriter } from '../../sql/Client';
import { App } from '../../components/App';
import OS from '../../util/os/osMain';
import { getConversation } from '../../util/getConversation';
@ -101,7 +102,7 @@ async function uploadProfile({
us.set('profileName', firstName);
us.set('profileFamilyName', lastName);
us.captureChange('standaloneProfile');
await window.Signal.Data.updateConversation(us.attributes);
await DataWriter.updateConversation(us.attributes);
await writeProfile(getConversation(us), {
keepAvatar: true,

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
import React, { memo, useCallback, useEffect, useMemo } from 'react';
import { useSelector } from 'react-redux';
import { DataReader } from '../../sql/Client';
import { useItemsActions } from '../ducks/items';
import {
getNavTabsCollapsed,
@ -184,7 +185,7 @@ export const SmartCallsTab = memo(function SmartCallsTab() {
if (callHistoryFilter == null) {
return 0;
}
const count = await window.Signal.Data.getCallHistoryGroupsCount(
const count = await DataReader.getCallHistoryGroupsCount(
callHistoryFilter
);
return count;
@ -206,7 +207,7 @@ export const SmartCallsTab = memo(function SmartCallsTab() {
if (callHistoryFilter == null) {
return [];
}
const results = await window.Signal.Data.getCallHistoryGroups(
const results = await DataReader.getCallHistoryGroups(
callHistoryFilter,
pagination
);

View file

@ -4,6 +4,7 @@
import { assert } from 'chai';
import { strictAssert } from '../util/assert';
import { DataWriter } from '../sql/Client';
import type { ConversationModel } from '../models/conversations';
import type { AciString, PniString, ServiceIdString } from '../types/ServiceId';
@ -32,7 +33,7 @@ describe('ConversationController', () => {
) => Promise<void>;
beforeEach(async () => {
await window.Signal.Data._removeAllConversations();
await DataWriter._removeAllConversations();
window.ConversationController.reset();
await window.ConversationController.load();

View file

@ -6,6 +6,7 @@ import { assert } from 'chai';
import { type AciString, generateAci } from '../types/ServiceId';
import type { MessageAttributesType } from '../model-types';
import { DataReader, DataWriter } from '../sql/Client';
import { SendStatus } from '../messages/MessageSendState';
import type {
MessageReceiptAttributesType,
@ -77,7 +78,7 @@ describe('MessageReceipts', () => {
},
};
await window.Signal.Data.saveMessage(messageAttributes, {
await DataWriter.saveMessage(messageAttributes, {
forceSave: true,
ourAci,
});
@ -97,7 +98,7 @@ describe('MessageReceipts', () => {
),
]);
const messageFromDatabase = await window.Signal.Data.getMessageById(id);
const messageFromDatabase = await DataReader.getMessageById(id);
const savedSendState = messageFromDatabase?.sendStateByConversationId;
assert.equal(savedSendState?.aaaa.status, SendStatus.Read, 'aaaa');
@ -154,11 +155,11 @@ describe('MessageReceipts', () => {
],
};
await window.Signal.Data.saveMessage(messageAttributes, {
await DataWriter.saveMessage(messageAttributes, {
forceSave: true,
ourAci,
});
await window.Signal.Data.saveEditedMessage(messageAttributes, ourAci, {
await DataWriter.saveEditedMessage(messageAttributes, ourAci, {
conversationId: messageAttributes.conversationId,
messageId: messageAttributes.id,
readStatus: ReadStatus.Read,
@ -211,7 +212,7 @@ describe('MessageReceipts', () => {
),
]);
const messageFromDatabase = await window.Signal.Data.getMessageById(id);
const messageFromDatabase = await DataReader.getMessageById(id);
const rootSendState = messageFromDatabase?.sendStateByConversationId;
assert.deepEqual(

View file

@ -17,6 +17,7 @@ import {
} from '@signalapp/libsignal-client';
import { v4 as generateUuid } from 'uuid';
import { DataReader, DataWriter } from '../sql/Client';
import { signal } from '../protobuf/compiled';
import { sessionStructureToBytes } from '../util/sessionTranslation';
import * as durations from '../util/durations';
@ -295,21 +296,21 @@ describe('SignalProtocolStore', () => {
await store.saveIdentity(identifier, testKey.pubKey);
});
it('marks the key firstUse', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert(identity.firstUse);
});
it('sets the timestamp', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert(identity.timestamp);
});
it('sets the verified status to DEFAULT', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -321,7 +322,7 @@ describe('SignalProtocolStore', () => {
const oldTimestamp = Date.now();
before(async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
firstUse: true,
@ -334,14 +335,14 @@ describe('SignalProtocolStore', () => {
await store.saveIdentity(identifier, newIdentity);
});
it('marks the key not firstUse', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert(!identity.firstUse);
});
it('updates the timestamp', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -350,7 +351,7 @@ describe('SignalProtocolStore', () => {
describe('The previous verified status was DEFAULT', () => {
before(async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
firstUse: true,
@ -363,9 +364,7 @@ describe('SignalProtocolStore', () => {
await store.saveIdentity(identifier, newIdentity);
});
it('sets the new key to default', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -374,7 +373,7 @@ describe('SignalProtocolStore', () => {
});
describe('The previous verified status was VERIFIED', () => {
before(async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
firstUse: true,
@ -387,9 +386,7 @@ describe('SignalProtocolStore', () => {
await store.saveIdentity(identifier, newIdentity);
});
it('sets the new key to unverified', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -401,7 +398,7 @@ describe('SignalProtocolStore', () => {
});
describe('The previous verified status was UNVERIFIED', () => {
before(async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
firstUse: true,
@ -414,9 +411,7 @@ describe('SignalProtocolStore', () => {
await store.saveIdentity(identifier, newIdentity);
});
it('sets the new key to unverified', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -430,7 +425,7 @@ describe('SignalProtocolStore', () => {
describe('When the key has not changed', () => {
const oldTimestamp = Date.now();
before(async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
timestamp: oldTimestamp,
@ -442,22 +437,18 @@ describe('SignalProtocolStore', () => {
});
describe('If it is marked firstUse', () => {
before(async () => {
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
identity.firstUse = true;
await window.Signal.Data.createOrUpdateIdentityKey(identity);
await DataWriter.createOrUpdateIdentityKey(identity);
await store.hydrateCaches();
});
it('nothing changes', async () => {
await store.saveIdentity(identifier, testKey.pubKey, true);
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -467,36 +458,30 @@ describe('SignalProtocolStore', () => {
});
describe('If it is not marked firstUse', () => {
before(async () => {
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
identity.firstUse = false;
await window.Signal.Data.createOrUpdateIdentityKey(identity);
await DataWriter.createOrUpdateIdentityKey(identity);
await store.hydrateCaches();
});
describe('If nonblocking approval is required', () => {
let now: number;
before(async () => {
now = Date.now();
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
identity.timestamp = now;
await window.Signal.Data.createOrUpdateIdentityKey(identity);
await DataWriter.createOrUpdateIdentityKey(identity);
await store.hydrateCaches();
});
it('sets non-blocking approval', async () => {
await store.saveIdentity(identifier, testKey.pubKey, true);
const identity = await window.Signal.Data.getIdentityKeyById(
theirAci
);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -532,35 +517,35 @@ describe('SignalProtocolStore', () => {
});
it('publicKey is saved', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert.isTrue(constantTimeEqual(identity.publicKey, testKey.pubKey));
});
it('firstUse is saved', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert.strictEqual(identity.firstUse, true);
});
it('timestamp is saved', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert.strictEqual(identity.timestamp, now);
});
it('verified is saved', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
assert.strictEqual(identity.verified, store.VerifiedStatus.VERIFIED);
});
it('nonblockingApproval is saved', async () => {
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -607,7 +592,7 @@ describe('SignalProtocolStore', () => {
describe('setApproval', () => {
it('sets nonblockingApproval', async () => {
await store.setApproval(theirAci, true);
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -617,7 +602,7 @@ describe('SignalProtocolStore', () => {
});
describe('setVerified', () => {
async function saveRecordDefault() {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
firstUse: true,
@ -632,7 +617,7 @@ describe('SignalProtocolStore', () => {
it('updates the verified status', async () => {
await store.setVerified(theirAci, store.VerifiedStatus.VERIFIED);
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -646,7 +631,7 @@ describe('SignalProtocolStore', () => {
it('updates the verified status', async () => {
await store.setVerified(theirAci, store.VerifiedStatus.VERIFIED);
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -667,7 +652,7 @@ describe('SignalProtocolStore', () => {
keychangeTriggered += 1;
});
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
timestamp: Date.now() - 10 * 1000 * 60,
@ -693,7 +678,7 @@ describe('SignalProtocolStore', () => {
assert.isFalse(needsNotification);
assert.strictEqual(keychangeTriggered, 0);
const identity = await window.Signal.Data.getIdentityKeyById(newAci);
const identity = await DataReader.getIdentityKeyById(newAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -712,7 +697,7 @@ describe('SignalProtocolStore', () => {
assert.isTrue(needsNotification);
assert.strictEqual(keychangeTriggered, 0);
const identity = await window.Signal.Data.getIdentityKeyById(newAci);
const identity = await DataReader.getIdentityKeyById(newAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -729,7 +714,7 @@ describe('SignalProtocolStore', () => {
assert.isFalse(needsNotification);
assert.strictEqual(keychangeTriggered, 1);
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -746,7 +731,7 @@ describe('SignalProtocolStore', () => {
assert.isTrue(needsNotification);
assert.strictEqual(keychangeTriggered, 0);
const identity = await window.Signal.Data.getIdentityKeyById(theirAci);
const identity = await DataReader.getIdentityKeyById(theirAci);
if (!identity) {
throw new Error('Missing identity!');
}
@ -757,7 +742,7 @@ describe('SignalProtocolStore', () => {
describe('isUntrusted', () => {
it('returns false if identity key old enough', async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
timestamp: Date.now() - 10 * 1000 * 60,
@ -772,7 +757,7 @@ describe('SignalProtocolStore', () => {
});
it('returns false if new but nonblockingApproval is true', async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
timestamp: Date.now(),
@ -787,7 +772,7 @@ describe('SignalProtocolStore', () => {
});
it('returns false if new but firstUse is true', async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
timestamp: Date.now(),
@ -802,7 +787,7 @@ describe('SignalProtocolStore', () => {
});
it('returns true if new, and no flags are set', async () => {
await window.Signal.Data.createOrUpdateIdentityKey({
await DataWriter.createOrUpdateIdentityKey({
id: theirAci,
publicKey: testKey.pubKey,
timestamp: Date.now(),

View file

@ -10,7 +10,7 @@ import { assert } from 'chai';
import type { ConversationModel } from '../../models/conversations';
import * as Bytes from '../../Bytes';
import Data from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import { type AciString, generateAci } from '../../types/ServiceId';
import { ReadStatus } from '../../messages/MessageReadStatus';
import { SeenStatus } from '../../MessageSeenStatus';
@ -39,8 +39,8 @@ describe('backup/attachments', () => {
let contactA: ConversationModel;
beforeEach(async () => {
await Data._removeAllMessages();
await Data._removeAllConversations();
await DataWriter._removeAllMessages();
await DataWriter._removeAllConversations();
window.storage.reset();
await setupBasics();

View file

@ -3,7 +3,7 @@
import { v4 as generateGuid } from 'uuid';
import Data from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import { SignalService as Proto } from '../../protobuf';
import { generateAci, generatePni } from '../../types/ServiceId';
@ -73,8 +73,8 @@ function createMessage(
describe('backup/groupv2/notifications', () => {
beforeEach(async () => {
await Data._removeAllMessages();
await Data._removeAllConversations();
await DataWriter._removeAllMessages();
await DataWriter._removeAllConversations();
window.storage.reset();
await setupBasics();

View file

@ -7,7 +7,7 @@ import { SendStatus } from '../../messages/MessageSendState';
import type { ConversationModel } from '../../models/conversations';
import { GiftBadgeStates } from '../../components/conversation/Message';
import Data from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import { getRandomBytes } from '../../Crypto';
import * as Bytes from '../../Bytes';
import { generateAci } from '../../types/ServiceId';
@ -39,8 +39,8 @@ describe('backup/bubble messages', () => {
let gv1: ConversationModel;
beforeEach(async () => {
await Data._removeAllMessages();
await Data._removeAllConversations();
await DataWriter._removeAllMessages();
await DataWriter._removeAllConversations();
window.storage.reset();
await setupBasics();

View file

@ -5,6 +5,7 @@ import Long from 'long';
import { join } from 'path';
import * as sinon from 'sinon';
import { BackupLevel } from '@signalapp/libsignal-client/zkgroup';
import { DataWriter } from '../../sql/Client';
import { Backups } from '../../protobuf';
import {
getFilePointerForAttachment,
@ -552,7 +553,7 @@ describe('getBackupJobForAttachmentAndFilePointer', async () => {
await window.storage.put('masterKey', Bytes.toBase64(getRandomBytes(32)));
});
afterEach(async () => {
await window.Signal.Data.removeAll();
await DataWriter.removeAll();
});
const attachment = composeAttachment();

View file

@ -23,7 +23,7 @@ import type {
import { backupsService } from '../../services/backups';
import { isUnsupportedMessage } from '../../state/selectors/message';
import { generateAci, generatePni } from '../../types/ServiceId';
import Data from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { getRandomBytes } from '../../Crypto';
import * as Bytes from '../../Bytes';
@ -145,7 +145,7 @@ export async function symmetricRoundtripHarness(
}
async function updateConvoIdToTitle() {
const all = await Data.getAllConversations();
const all = await DataReader.getAllConversations();
for (const convo of all) {
CONVO_ID_TO_STABLE_ID.set(
convo.id,
@ -167,7 +167,7 @@ export async function asymmetricRoundtripHarness(
try {
const targetOutputFile = path.join(outDir, 'backup.bin');
await Data.saveMessages(before, { forceSave: true, ourAci: OUR_ACI });
await DataWriter.saveMessages(before, { forceSave: true, ourAci: OUR_ACI });
await backupsService.exportToDisk(targetOutputFile, options.backupLevel);
@ -177,7 +177,7 @@ export async function asymmetricRoundtripHarness(
await backupsService.importBackup(() => createReadStream(targetOutputFile));
const messagesFromDatabase = await Data._getAllMessages();
const messagesFromDatabase = await DataReader._getAllMessages();
await updateConvoIdToTitle();
@ -199,9 +199,9 @@ export async function asymmetricRoundtripHarness(
}
async function clearData() {
await Data._removeAllMessages();
await Data._removeAllConversations();
await Data.removeAllItems();
await DataWriter._removeAllMessages();
await DataWriter._removeAllConversations();
await DataWriter.removeAllItems();
window.storage.reset();
window.ConversationController.reset();

View file

@ -9,7 +9,7 @@ import type { ConversationModel } from '../../models/conversations';
import { getRandomBytes } from '../../Crypto';
import * as Bytes from '../../Bytes';
import { SignalService as Proto, Backups } from '../../protobuf';
import Data from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import { generateAci } from '../../types/ServiceId';
import { PaymentEventKind } from '../../types/Payment';
import { ContactFormType } from '../../types/EmbeddedContact';
@ -32,8 +32,8 @@ describe('backup/non-bubble messages', () => {
let group: ConversationModel;
beforeEach(async () => {
await Data._removeAllMessages();
await Data._removeAllConversations();
await DataWriter._removeAllMessages();
await DataWriter._removeAllConversations();
window.storage.reset();
await setupBasics();

View file

@ -4,6 +4,7 @@
import { assert } from 'chai';
import { v4 as generateUuid } from 'uuid';
import { DataWriter } from '../../sql/Client';
import { SendStatus } from '../../messages/MessageSendState';
import { IMAGE_PNG } from '../../types/MIME';
import { generateAci, generatePni } from '../../types/ServiceId';
@ -79,7 +80,7 @@ describe('Conversations', () => {
});
// Saving to db and updating the convo's last message
await window.Signal.Data.saveMessage(message.attributes, {
await DataWriter.saveMessage(message.attributes, {
forceSave: true,
ourAci,
});
@ -88,7 +89,7 @@ describe('Conversations', () => {
message,
'test'
);
await window.Signal.Data.updateConversation(conversation.attributes);
await DataWriter.updateConversation(conversation.attributes);
await conversation.updateLastMessage();
// Should be set to bananas because that's the last message sent.

Some files were not shown because too many files have changed in this diff Show more