remove the forceSave logic for a message, always insert or replace

pull/1495/head
Audric Ackermann 4 years ago
parent 7e77a3f3b6
commit 3ee0ccfac8

@ -1716,7 +1716,7 @@ async function getMessageCount() {
return row['count(*)']; return row['count(*)'];
} }
async function saveMessage(data, { forceSave } = {}) { async function saveMessage(data) {
const { const {
body, body,
conversationId, conversationId,
@ -1742,6 +1742,14 @@ async function saveMessage(data, { forceSave } = {}) {
expirationStartTimestamp, expirationStartTimestamp,
} = data; } = data;
if (!id) {
throw new Error('id is required');
}
if (!conversationId) {
throw new Error('conversationId is required');
}
const payload = { const payload = {
$id: id, $id: id,
$json: objectToJSON(data), $json: objectToJSON(data),
@ -1766,46 +1774,10 @@ async function saveMessage(data, { forceSave } = {}) {
$unread: unread, $unread: unread,
}; };
if (id && !forceSave) {
await db.run(
`UPDATE messages SET
json = $json,
serverId = $serverId,
serverTimestamp = $serverTimestamp,
body = $body,
conversationId = $conversationId,
expirationStartTimestamp = $expirationStartTimestamp,
expires_at = $expires_at,
expireTimer = $expireTimer,
hasAttachments = $hasAttachments,
hasFileAttachments = $hasFileAttachments,
hasVisualMediaAttachments = $hasVisualMediaAttachments,
id = $id,
received_at = $received_at,
schemaVersion = $schemaVersion,
sent = $sent,
sent_at = $sent_at,
source = $source,
sourceDevice = $sourceDevice,
type = $type,
unread = $unread
WHERE id = $id;`,
payload
);
return id;
}
const toCreate = {
...data,
id: id || uuidv4(),
};
await db.run( await db.run(
`INSERT INTO messages ( `INSERT OR REPLACE INTO ${MESSAGES_TABLE} (
id, id,
json, json,
serverId, serverId,
serverTimestamp, serverTimestamp,
body, body,
@ -1827,7 +1799,6 @@ async function saveMessage(data, { forceSave } = {}) {
) values ( ) values (
$id, $id,
$json, $json,
$serverId, $serverId,
$serverTimestamp, $serverTimestamp,
$body, $body,
@ -1849,12 +1820,11 @@ async function saveMessage(data, { forceSave } = {}) {
);`, );`,
{ {
...payload, ...payload,
$id: toCreate.id, $json: objectToJSON(data),
$json: objectToJSON(toCreate),
} }
); );
return toCreate.id; return id;
} }
async function saveSeenMessageHashes(arrayOfHashes) { async function saveSeenMessageHashes(arrayOfHashes) {
@ -1926,13 +1896,13 @@ async function cleanSeenMessages() {
}); });
} }
async function saveMessages(arrayOfMessages, { forceSave } = {}) { async function saveMessages(arrayOfMessages) {
let promise; let promise;
db.serialize(() => { db.serialize(() => {
promise = Promise.all([ promise = Promise.all([
db.run('BEGIN TRANSACTION;'), db.run('BEGIN TRANSACTION;'),
...map(arrayOfMessages, message => saveMessage(message, { forceSave })), ...map(arrayOfMessages, message => saveMessage(message)),
db.run('COMMIT TRANSACTION;'), db.run('COMMIT TRANSACTION;'),
]); ]);
}); });
@ -2175,7 +2145,7 @@ async function getNextExpiringMessage() {
async function saveUnprocessed(data, { forceSave } = {}) { async function saveUnprocessed(data, { forceSave } = {}) {
const { id, timestamp, version, attempts, envelope, senderIdentity } = data; const { id, timestamp, version, attempts, envelope, senderIdentity } = data;
if (!id) { if (!id) {
throw new Error('saveUnprocessed: id was falsey'); throw new Error(`saveUnprocessed: id was falsey: ${id}`);
} }
if (forceSave) { if (forceSave) {

@ -386,7 +386,6 @@ window.autoOrientImage = autoOrientImage;
window.loadImage = require('blueimp-load-image'); window.loadImage = require('blueimp-load-image');
window.dataURLToBlobSync = require('blueimp-canvas-to-blob'); window.dataURLToBlobSync = require('blueimp-canvas-to-blob');
window.filesize = require('filesize'); window.filesize = require('filesize');
window.getGuid = require('uuid/v4');
window.profileImages = require('./app/profile_images'); window.profileImages = require('./app/profile_images');
window.React = require('react'); window.React = require('react');

@ -489,7 +489,6 @@ describe('Backup', () => {
const message = await upgradeMessageSchema(messageWithAttachments); const message = await upgradeMessageSchema(messageWithAttachments);
await window.Signal.Data.saveMessage(message, { await window.Signal.Data.saveMessage(message, {
Message: window.models.Message.MessageModel, Message: window.models.Message.MessageModel,
forceSave: true,
}); });
const conversation = { const conversation = {

@ -65,8 +65,6 @@ export type ServerToken = {
}; };
const channelsToMake = { const channelsToMake = {
_cleanData,
shutdown, shutdown,
close, close,
removeDB, removeDB,
@ -205,7 +203,7 @@ export function init() {
// When IPC arguments are prepared for the cross-process send, they are JSON.stringified. // When IPC arguments are prepared for the cross-process send, they are JSON.stringified.
// We can't send ArrayBuffers or BigNumbers (what we get from proto library for dates). // We can't send ArrayBuffers or BigNumbers (what we get from proto library for dates).
export async function _cleanData(data: any): Promise<any> { function _cleanData(data: any): any {
const keys = Object.keys(data); const keys = Object.keys(data);
for (let index = 0, max = keys.length; index < max; index += 1) { for (let index = 0, max = keys.length; index < max; index += 1) {
const key = keys[index]; const key = keys[index];
@ -691,13 +689,8 @@ export async function updateLastHash(data: any): Promise<void> {
await channels.updateLastHash(_cleanData(data)); await channels.updateLastHash(_cleanData(data));
} }
export async function saveMessage( export async function saveMessage(data: MessageModel): Promise<string> {
data: MessageModel, const id = await channels.saveMessage(_cleanData(data));
options?: { forceSave: boolean }
): Promise<string> {
const id = await channels.saveMessage(_cleanData(data), {
forceSave: options?.forceSave,
});
window.Whisper.ExpiringMessagesListener.update(); window.Whisper.ExpiringMessagesListener.update();
return id; return id;
} }
@ -797,7 +790,6 @@ export async function getMessagesByConversation(
receivedAt, receivedAt,
type, type,
}); });
return new MessageCollection(messages); return new MessageCollection(messages);
} }

@ -936,7 +936,6 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
destination: this.id, destination: this.id,
recipients: isOutgoing ? this.getRecipients() : undefined, recipients: isOutgoing ? this.getRecipients() : undefined,
}; };
const message = await this.addSingleMessage(messageAttributes); const message = await this.addSingleMessage(messageAttributes);
// tell the UI this conversation was updated // tell the UI this conversation was updated

@ -44,6 +44,7 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
// this.on('expired', this.onExpired); // this.on('expired', this.onExpired);
void this.setToExpire(); void this.setToExpire();
autoBind(this); autoBind(this);
this.markRead = this.markRead.bind(this); this.markRead = this.markRead.bind(this);
// Keep props ready // Keep props ready
const generateProps = (triggerEvent = true) => { const generateProps = (triggerEvent = true) => {
@ -207,14 +208,16 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
return window.i18n('mediaMessage'); return window.i18n('mediaMessage');
} }
if (this.isExpirationTimerUpdate()) { if (this.isExpirationTimerUpdate()) {
const { expireTimer } = this.get('expirationTimerUpdate'); const expireTimerUpdate = this.get('expirationTimerUpdate');
if (!expireTimer) { if (!expireTimerUpdate || !expireTimerUpdate.expireTimer) {
return window.i18n('disappearingMessagesDisabled'); return window.i18n('disappearingMessagesDisabled');
} }
return window.i18n( return window.i18n(
'timerSetTo', 'timerSetTo',
window.Whisper.ExpirationTimerOptions.getAbbreviated(expireTimer || 0) window.Whisper.ExpirationTimerOptions.getAbbreviated(
expireTimerUpdate.expireTimer || 0
)
); );
} }
const contacts = this.get('contact'); const contacts = this.get('contact');
@ -1234,11 +1237,11 @@ export class MessageModel extends Backbone.Model<MessageAttributes> {
await this.commit(); await this.commit();
} }
public async commit(forceSave = false) { public async commit() {
// TODO investigate the meaning of the forceSave if (!this.attributes.id) {
const id = await saveMessage(this.attributes, { throw new Error('A message always needs an id');
forceSave, }
}); const id = await saveMessage(this.attributes);
this.trigger('change'); this.trigger('change');
return id; return id;
} }

@ -1,5 +1,6 @@
import { DefaultTheme } from 'styled-components'; import { DefaultTheme } from 'styled-components';
import _ from 'underscore'; import _ from 'underscore';
import uuidv4 from 'uuid';
import { QuotedAttachmentType } from '../components/conversation/Quote'; import { QuotedAttachmentType } from '../components/conversation/Quote';
import { AttachmentType } from '../types/Attachment'; import { AttachmentType } from '../types/Attachment';
import { Contact } from '../types/Contact'; import { Contact } from '../types/Contact';
@ -43,7 +44,12 @@ export interface MessageAttributes {
hasFileAttachments: boolean; hasFileAttachments: boolean;
hasVisualMediaAttachments: boolean; hasVisualMediaAttachments: boolean;
schemaVersion: number; schemaVersion: number;
expirationTimerUpdate?: any; expirationTimerUpdate?: {
expireTimer: number;
source: string;
fromSync?: boolean;
fromGroupUpdate?: boolean;
};
unread: boolean; unread: boolean;
group?: any; group?: any;
timestamp?: number; timestamp?: number;
@ -91,7 +97,12 @@ export interface MessageAttributesOptionals {
hasFileAttachments?: boolean; hasFileAttachments?: boolean;
hasVisualMediaAttachments?: boolean; hasVisualMediaAttachments?: boolean;
schemaVersion?: number; schemaVersion?: number;
expirationTimerUpdate?: any; expirationTimerUpdate?: {
expireTimer: number;
source: string;
fromSync?: boolean;
fromGroupUpdate?: boolean;
};
unread?: boolean; unread?: boolean;
group?: any; group?: any;
timestamp?: number; timestamp?: number;
@ -120,6 +131,7 @@ export const fillMessageAttributesWithDefaults = (
//FIXME audric to do put the default //FIXME audric to do put the default
return _.defaults(optAttributes, { return _.defaults(optAttributes, {
expireTimer: 0, // disabled expireTimer: 0, // disabled
id: uuidv4(),
}); });
}; };

@ -37,13 +37,10 @@ export async function addToCache(
if (envelope.senderIdentity) { if (envelope.senderIdentity) {
data.senderIdentity = envelope.senderIdentity; data.senderIdentity = envelope.senderIdentity;
} }
return saveUnprocessed(data, { forceSave: true }); return saveUnprocessed(data, { forceSave: true });
} }
async function fetchAllFromCache(): Promise<Array<any>> { async function fetchAllFromCache(): Promise<Array<any>> {
const { textsecure } = window;
const count = await getUnprocessedCount(); const count = await getUnprocessedCount();
if (count > 1500) { if (count > 1500) {
@ -63,7 +60,6 @@ export async function getAllFromCache() {
const items = await fetchAllFromCache(); const items = await fetchAllFromCache();
window.log.info('getAllFromCache loaded', items.length, 'saved envelopes'); window.log.info('getAllFromCache loaded', items.length, 'saved envelopes');
const { textsecure } = window;
return Promise.all( return Promise.all(
_.map(items, async (item: any) => { _.map(items, async (item: any) => {
@ -104,7 +100,6 @@ export async function getAllFromCacheForSource(source: string) {
itemsFromSource.length, itemsFromSource.length,
'saved envelopes' 'saved envelopes'
); );
const { textsecure } = window;
return Promise.all( return Promise.all(
_.map(items, async (item: any) => { _.map(items, async (item: any) => {

@ -2,6 +2,7 @@
import { EnvelopePlus } from './types'; import { EnvelopePlus } from './types';
export { downloadAttachment } from './attachments'; export { downloadAttachment } from './attachments';
import uuidv4 from 'uuid';
import { import {
addToCache, addToCache,
@ -27,6 +28,7 @@ import { getEnvelopeId } from './common';
import { StringUtils, UserUtils } from '../session/utils'; import { StringUtils, UserUtils } from '../session/utils';
import { SignalService } from '../protobuf'; import { SignalService } from '../protobuf';
import { ConversationController } from '../session/conversations'; import { ConversationController } from '../session/conversations';
import { removeUnprocessed } from '../data/data';
// TODO: check if some of these exports no longer needed // TODO: check if some of these exports no longer needed
@ -131,7 +133,7 @@ async function handleRequestDetail(
envelope.senderIdentity = senderIdentity; envelope.senderIdentity = senderIdentity;
} }
envelope.id = envelope.serverGuid || window.getGuid(); envelope.id = envelope.serverGuid || uuidv4();
envelope.serverTimestamp = envelope.serverTimestamp envelope.serverTimestamp = envelope.serverTimestamp
? envelope.serverTimestamp.toNumber() ? envelope.serverTimestamp.toNumber()
: null; : null;

@ -92,7 +92,10 @@ export class ChatMessage extends DataMessage {
profileKey: dataMessage.profileKey, profileKey: dataMessage.profileKey,
}; };
if ((dataMessage as any)?.$type?.name !== 'DataMessage' && !(dataMessage instanceof DataMessage)) { if (
(dataMessage as any)?.$type?.name !== 'DataMessage' &&
!(dataMessage instanceof DataMessage)
) {
throw new Error( throw new Error(
'Tried to build a sync message from something else than a DataMessage' 'Tried to build a sync message from something else than a DataMessage'
); );

1
ts/window.d.ts vendored

@ -90,7 +90,6 @@ declare global {
versionInfo: any; versionInfo: any;
getStoragePubKey: (key: string) => string; getStoragePubKey: (key: string) => string;
getConversations: () => ConversationCollection; getConversations: () => ConversationCollection;
getGuid: any;
SwarmPolling: SwarmPolling; SwarmPolling: SwarmPolling;
SnodePool: { SnodePool: {
getSnodesFor: (string) => any; getSnodesFor: (string) => any;

Loading…
Cancel
Save