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

@ -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.

View file

@ -13,6 +13,7 @@ import type { MessageModel } from '../../models/messages';
import type { RawBodyRange } from '../../types/BodyRange';
import type { StorageAccessType } from '../../types/Storage.d';
import type { WebAPIType } from '../../textsecure/WebAPI';
import { DataWriter } from '../../sql/Client';
import MessageSender from '../../textsecure/SendMessage';
import enMessages from '../../../_locales/en/messages.json';
import { SendStatus } from '../../messages/MessageSendState';
@ -78,7 +79,7 @@ describe('Message', () => {
});
after(async () => {
await window.Signal.Data.removeAll();
await DataWriter.removeAll();
await window.storage.fetch();
await Promise.all(

View file

@ -19,7 +19,7 @@ import type {
StandardAttachmentBackupJobType,
ThumbnailAttachmentBackupJobType,
} from '../../types/AttachmentBackup';
import dataInterface from '../../sql/Client';
import { DataWriter } from '../../sql/Client';
import { getRandomBytes } from '../../Crypto';
import { APPLICATION_OCTET_STREAM, VIDEO_MP4 } from '../../types/MIME';
import { createName, getRelativePath } from '../../util/attachmentPath';
@ -98,7 +98,7 @@ describe('AttachmentBackupManager/JobManager', () => {
}
beforeEach(async () => {
await dataInterface.removeAll();
await DataWriter.removeAll();
await window.storage.put('masterKey', Bytes.toBase64(getRandomBytes(32)));
sandbox = sinon.createSandbox();
@ -214,7 +214,7 @@ describe('AttachmentBackupManager/JobManager', () => {
}
async function getAllSavedJobs(): Promise<Array<AttachmentBackupJobType>> {
return dataInterface.getNextAttachmentBackupJobs({
return DataWriter.getNextAttachmentBackupJobs({
limit: 1000,
timestamp: Infinity,
});

View file

@ -15,7 +15,7 @@ import {
type NewAttachmentDownloadJobType,
} from '../../jobs/AttachmentDownloadManager';
import type { AttachmentDownloadJobType } from '../../types/AttachmentDownload';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { MINUTE } from '../../util/durations';
import { type AciString } from '../../types/ServiceId';
import { type AttachmentType, AttachmentVariant } from '../../types/Attachment';
@ -60,7 +60,7 @@ describe('AttachmentDownloadManager/JobManager', () => {
let isInCall: sinon.SinonStub;
beforeEach(async () => {
await dataInterface.removeAll();
await DataWriter.removeAll();
sandbox = sinon.createSandbox();
clock = sandbox.useFakeTimers();
@ -99,7 +99,7 @@ describe('AttachmentDownloadManager/JobManager', () => {
urgency: AttachmentDownloadUrgency
) {
// Save message first to satisfy foreign key constraint
await dataInterface.saveMessage(
await DataWriter.saveMessage(
{
id: job.messageId,
type: 'incoming',
@ -162,13 +162,13 @@ describe('AttachmentDownloadManager/JobManager', () => {
// first. In cases like maybeStartJobs where we prevent re-entrancy, without this,
// prior (unfinished) invocations can prevent subsequent calls after the clock is
// ticked forward and make tests unreliable
await dataInterface.getAllItems();
await DataReader.getAllItems();
const now = Date.now();
while (Date.now() < now + ms) {
// eslint-disable-next-line no-await-in-loop
await clock.tickAsync(downloadManager?.tickInterval ?? 1000);
// eslint-disable-next-line no-await-in-loop
await dataInterface.getAllItems();
await DataReader.getAllItems();
}
}
@ -187,7 +187,7 @@ describe('AttachmentDownloadManager/JobManager', () => {
it('runs 3 jobs at a time in descending receivedAt order', async () => {
const jobs = await addJobs(5);
// Confirm they are saved to DB
const allJobs = await dataInterface.getNextAttachmentDownloadJobs({
const allJobs = await DataWriter.getNextAttachmentDownloadJobs({
limit: 100,
});
@ -298,8 +298,8 @@ describe('AttachmentDownloadManager/JobManager', () => {
assert.strictEqual(runJob.callCount, 2);
assertRunJobCalledWith([jobs[1], jobs[0]]);
const retriedJob = await dataInterface.getAttachmentDownloadJob(jobs[1]);
const finishedJob = await dataInterface.getAttachmentDownloadJob(jobs[0]);
const retriedJob = await DataReader.getAttachmentDownloadJob(jobs[1]);
const finishedJob = await DataReader.getAttachmentDownloadJob(jobs[0]);
assert.isUndefined(finishedJob);
assert.strictEqual(retriedJob?.attempts, 1);
@ -332,7 +332,7 @@ describe('AttachmentDownloadManager/JobManager', () => {
]);
// Ensure it's been removed after completed
assert.isUndefined(await dataInterface.getAttachmentDownloadJob(jobs[1]));
assert.isUndefined(await DataReader.getAttachmentDownloadJob(jobs[1]));
});
it('will reset attempts if addJob is called again', async () => {
@ -382,7 +382,7 @@ describe('AttachmentDownloadManager/JobManager', () => {
assert.strictEqual(runJob.callCount, 8);
// Ensure it's been removed
assert.isUndefined(await dataInterface.getAttachmentDownloadJob(jobs[0]));
assert.isUndefined(await DataReader.getAttachmentDownloadJob(jobs[0]));
});
});

View file

@ -4,6 +4,7 @@
import { assert } from 'chai';
import { v4 as uuid } from 'uuid';
import type { MessageAttributesType } from '../../model-types.d';
import { DataReader, DataWriter } from '../../sql/Client';
import { MessageModel } from '../../models/messages';
import { strictAssert } from '../../util/assert';
@ -358,7 +359,7 @@ describe('MessageCache', () => {
timestamp: Date.now(),
type: 'incoming',
};
await window.Signal.Data.saveMessage(messageAttributes, {
await DataWriter.saveMessage(messageAttributes, {
forceSave: true,
ourAci,
});
@ -379,7 +380,7 @@ describe('MessageCache', () => {
skipSaveToDatabase: false,
});
const messageFromDatabase = await window.Signal.Data.getMessageById(id);
const messageFromDatabase = await DataReader.getMessageById(id);
assert.deepEqual(newAttributes, messageFromDatabase);
});

View file

@ -4,18 +4,17 @@
import { assert } from 'chai';
import { v4 as generateUuid } from 'uuid';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { generateAci } from '../../types/ServiceId';
import type { MessageAttributesType } from '../../model-types.d';
const {
removeAll,
_getAllMessages,
saveMessages,
getMessagesWithVisualMediaAttachments,
getMessagesWithFileAttachments,
} = dataInterface;
} = DataReader;
const { removeAll, saveMessages } = DataWriter;
describe('sql/allMedia', () => {
beforeEach(async () => {

View file

@ -4,18 +4,14 @@
import { assert } from 'chai';
import { v4 as generateUuid } from 'uuid';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { generateAci } from '../../types/ServiceId';
import { DurationInSeconds } from '../../util/durations';
import type { MessageAttributesType } from '../../model-types.d';
const {
removeAll,
_getAllMessages,
saveMessages,
getConversationMessageStats,
} = dataInterface;
const { _getAllMessages, getConversationMessageStats } = DataReader;
const { removeAll, saveMessages } = DataWriter;
describe('sql/conversationSummary', () => {
beforeEach(async () => {

View file

@ -4,18 +4,13 @@
import { assert } from 'chai';
import { v4 as generateUuid } from 'uuid';
import dataInterface from '../../sql/Client';
import { DataReader, DataWriter } from '../../sql/Client';
import { generateAci } from '../../types/ServiceId';
import type { MessageAttributesType } from '../../model-types.d';
const {
removeAll,
_getAllMessages,
saveMessages,
saveMessage,
searchMessages,
} = dataInterface;
const { _getAllMessages, searchMessages } = DataReader;
const { removeAll, saveMessages, saveMessage } = DataWriter;
describe('sql/searchMessages', () => {
beforeEach(async () => {

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