Receive support for View Once photos

This commit is contained in:
Scott Nonnenberg 2019-06-26 12:33:13 -07:00
parent fccf1eec30
commit e62a1a7812
38 changed files with 1937 additions and 102 deletions

View file

@ -94,6 +94,9 @@ module.exports = {
getOutgoingWithoutExpiresAt,
getNextExpiringMessage,
getMessagesByConversation,
getNextTapToViewMessageToExpire,
getNextTapToViewMessageToAgeOut,
getTapToViewMessagesNeedingErase,
getUnprocessedCount,
getAllUnprocessed,
@ -868,6 +871,87 @@ async function updateToSchemaVersion15(currentVersion, instance) {
}
}
async function updateToSchemaVersion16(currentVersion, instance) {
if (currentVersion >= 16) {
return;
}
console.log('updateToSchemaVersion16: starting...');
await instance.run('BEGIN TRANSACTION;');
try {
await instance.run(
`ALTER TABLE messages
ADD COLUMN messageTimer INTEGER;`
);
await instance.run(
`ALTER TABLE messages
ADD COLUMN messageTimerStart INTEGER;`
);
await instance.run(
`ALTER TABLE messages
ADD COLUMN messageTimerExpiresAt INTEGER;`
);
await instance.run(
`ALTER TABLE messages
ADD COLUMN isErased INTEGER;`
);
await instance.run(`CREATE INDEX messages_message_timer ON messages (
messageTimer,
messageTimerStart,
messageTimerExpiresAt,
isErased
) WHERE messageTimer IS NOT NULL;`);
// Updating full-text triggers to avoid anything with a messageTimer set
await instance.run('DROP TRIGGER messages_on_insert;');
await instance.run('DROP TRIGGER messages_on_delete;');
await instance.run('DROP TRIGGER messages_on_update;');
await instance.run(`
CREATE TRIGGER messages_on_insert AFTER INSERT ON messages
WHEN new.messageTimer IS NULL
BEGIN
INSERT INTO messages_fts (
id,
body
) VALUES (
new.id,
new.body
);
END;
`);
await instance.run(`
CREATE TRIGGER messages_on_delete AFTER DELETE ON messages BEGIN
DELETE FROM messages_fts WHERE id = old.id;
END;
`);
await instance.run(`
CREATE TRIGGER messages_on_update AFTER UPDATE ON messages
WHEN new.messageTimer IS NULL
BEGIN
DELETE FROM messages_fts WHERE id = old.id;
INSERT INTO messages_fts(
id,
body
) VALUES (
new.id,
new.body
);
END;
`);
await instance.run('PRAGMA schema_version = 16;');
await instance.run('COMMIT TRANSACTION;');
console.log('updateToSchemaVersion16: success!');
} catch (error) {
await instance.run('ROLLBACK;');
throw error;
}
}
const SCHEMA_VERSIONS = [
updateToSchemaVersion1,
updateToSchemaVersion2,
@ -884,6 +968,7 @@ const SCHEMA_VERSIONS = [
updateToSchemaVersion13,
updateToSchemaVersion14,
updateToSchemaVersion15,
updateToSchemaVersion16,
];
async function updateSchema(instance) {
@ -1480,6 +1565,10 @@ async function saveMessage(data, { forceSave } = {}) {
hasFileAttachments,
hasVisualMediaAttachments,
id,
isErased,
messageTimer,
messageTimerStart,
messageTimerExpiresAt,
// eslint-disable-next-line camelcase
received_at,
schemaVersion,
@ -1505,6 +1594,10 @@ async function saveMessage(data, { forceSave } = {}) {
$hasAttachments: hasAttachments,
$hasFileAttachments: hasFileAttachments,
$hasVisualMediaAttachments: hasVisualMediaAttachments,
$isErased: isErased,
$messageTimer: messageTimer,
$messageTimerStart: messageTimerStart,
$messageTimerExpiresAt: messageTimerExpiresAt,
$received_at: received_at,
$schemaVersion: schemaVersion,
$sent_at: sent_at,
@ -1517,7 +1610,9 @@ async function saveMessage(data, { forceSave } = {}) {
if (id && !forceSave) {
await db.run(
`UPDATE messages SET
id = $id,
json = $json,
body = $body,
conversationId = $conversationId,
expirationStartTimestamp = $expirationStartTimestamp,
@ -1526,7 +1621,10 @@ async function saveMessage(data, { forceSave } = {}) {
hasAttachments = $hasAttachments,
hasFileAttachments = $hasFileAttachments,
hasVisualMediaAttachments = $hasVisualMediaAttachments,
id = $id,
isErased = $isErased,
messageTimer = $messageTimer,
messageTimerStart = $messageTimerStart,
messageTimerExpiresAt = $messageTimerExpiresAt,
received_at = $received_at,
schemaVersion = $schemaVersion,
sent_at = $sent_at,
@ -1559,6 +1657,10 @@ async function saveMessage(data, { forceSave } = {}) {
hasAttachments,
hasFileAttachments,
hasVisualMediaAttachments,
isErased,
messageTimer,
messageTimerStart,
messageTimerExpiresAt,
received_at,
schemaVersion,
sent_at,
@ -1578,6 +1680,10 @@ async function saveMessage(data, { forceSave } = {}) {
$hasAttachments,
$hasFileAttachments,
$hasVisualMediaAttachments,
$isErased,
$messageTimer,
$messageTimerStart,
$messageTimerExpiresAt,
$received_at,
$schemaVersion,
$sent_at,
@ -1756,6 +1862,69 @@ async function getNextExpiringMessage() {
return map(rows, row => jsonToObject(row.json));
}
async function getNextTapToViewMessageToExpire() {
// Note: we avoid 'IS NOT NULL' here because it does seem to bypass our index
const rows = await db.all(`
SELECT json FROM messages
WHERE
messageTimer > 0
AND messageTimerExpiresAt > 0
AND (isErased IS NULL OR isErased != 1)
ORDER BY messageTimerExpiresAt ASC
LIMIT 1;
`);
if (!rows || rows.length < 1) {
return null;
}
return jsonToObject(rows[0].json);
}
async function getNextTapToViewMessageToAgeOut() {
// Note: we avoid 'IS NOT NULL' here because it does seem to bypass our index
const rows = await db.all(`
SELECT json FROM messages
WHERE
messageTimer > 0
AND (isErased IS NULL OR isErased != 1)
ORDER BY received_at ASC
LIMIT 1;
`);
if (!rows || rows.length < 1) {
return null;
}
return jsonToObject(rows[0].json);
}
async function getTapToViewMessagesNeedingErase() {
const THIRTY_DAYS_AGO = Date.now() - 30 * 24 * 60 * 60 * 1000;
const NOW = Date.now();
// Note: we avoid 'IS NOT NULL' here because it does seem to bypass our index
const rows = await db.all(
`SELECT json FROM messages
WHERE
messageTimer > 0
AND (isErased IS NULL OR isErased != 1)
AND (
(messageTimerExpiresAt > 0
AND messageTimerExpiresAt <= $NOW)
OR
received_at <= $THIRTY_DAYS_AGO
)
ORDER BY received_at ASC;`,
{
$NOW: NOW,
$THIRTY_DAYS_AGO: THIRTY_DAYS_AGO,
}
);
return map(rows, row => jsonToObject(row.json));
}
async function saveUnprocessed(data, { forceSave } = {}) {
const { id, timestamp, version, attempts, envelope } = data;
if (!id) {