2022-03-31 17:19:08 +00:00
|
|
|
let { existsSync, readFileSync } = require('fs');
|
|
|
|
let { join } = require('path');
|
|
|
|
let { openDatabase } = require('./db');
|
2022-09-15 14:16:20 +00:00
|
|
|
let config = require('./load-config');
|
2022-03-31 17:19:08 +00:00
|
|
|
|
|
|
|
let actual = require('@actual-app/api');
|
|
|
|
let merkle = actual.internal.merkle;
|
2022-09-02 15:44:39 +00:00
|
|
|
let SyncPb = actual.internal.SyncProtoBuf;
|
|
|
|
let Timestamp = actual.internal.timestamp.default;
|
2022-03-31 17:19:08 +00:00
|
|
|
|
|
|
|
function getGroupDb(groupId) {
|
2022-09-15 14:16:20 +00:00
|
|
|
let path = join(config.userFiles, `${groupId}.sqlite`);
|
2022-03-31 17:19:08 +00:00
|
|
|
let needsInit = !existsSync(path);
|
|
|
|
|
|
|
|
let db = openDatabase(path);
|
|
|
|
|
|
|
|
if (needsInit) {
|
|
|
|
let sql = readFileSync(join(__dirname, 'sql/messages.sql'), 'utf8');
|
|
|
|
db.exec(sql);
|
|
|
|
}
|
|
|
|
|
|
|
|
return db;
|
|
|
|
}
|
|
|
|
|
|
|
|
function addMessages(db, messages) {
|
|
|
|
let returnValue;
|
|
|
|
db.transaction(() => {
|
|
|
|
let trie = getMerkle(db);
|
|
|
|
|
|
|
|
if (messages.length > 0) {
|
|
|
|
for (let msg of messages) {
|
|
|
|
let info = db.mutate(
|
|
|
|
`INSERT OR IGNORE INTO messages_binary (timestamp, is_encrypted, content)
|
|
|
|
VALUES (?, ?, ?)`,
|
|
|
|
[
|
|
|
|
msg.getTimestamp(),
|
|
|
|
msg.getIsencrypted() ? 1 : 0,
|
|
|
|
Buffer.from(msg.getContent())
|
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
if (info.changes > 0) {
|
|
|
|
trie = merkle.insert(trie, Timestamp.parse(msg.getTimestamp()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
trie = merkle.prune(trie);
|
|
|
|
|
|
|
|
db.mutate(
|
|
|
|
'INSERT INTO messages_merkles (id, merkle) VALUES (1, ?) ON CONFLICT (id) DO UPDATE SET merkle = ?',
|
|
|
|
[JSON.stringify(trie), JSON.stringify(trie)]
|
|
|
|
);
|
|
|
|
|
|
|
|
returnValue = trie;
|
|
|
|
});
|
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
}
|
|
|
|
|
2022-09-15 03:34:16 +00:00
|
|
|
function getMerkle(db) {
|
2022-09-02 15:44:39 +00:00
|
|
|
let rows = db.all('SELECT * FROM messages_merkles');
|
2022-03-31 17:19:08 +00:00
|
|
|
|
|
|
|
if (rows.length > 0) {
|
|
|
|
return JSON.parse(rows[0].merkle);
|
|
|
|
} else {
|
|
|
|
// No merkle trie exists yet (first sync of the app), so create a
|
|
|
|
// default one.
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-02 15:44:39 +00:00
|
|
|
function sync(messages, since, groupId) {
|
|
|
|
let db = getGroupDb(groupId);
|
2022-03-31 17:19:08 +00:00
|
|
|
let newMessages = db.all(
|
|
|
|
`SELECT * FROM messages_binary
|
|
|
|
WHERE timestamp > ?
|
|
|
|
ORDER BY timestamp`,
|
2022-05-20 21:37:42 +00:00
|
|
|
[since]
|
2022-03-31 17:19:08 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
let trie = addMessages(db, messages);
|
|
|
|
|
2022-09-02 15:44:39 +00:00
|
|
|
db.close();
|
|
|
|
|
|
|
|
return {
|
|
|
|
trie,
|
2022-09-15 03:34:16 +00:00
|
|
|
newMessages: newMessages.map((msg) => {
|
2022-09-02 15:44:39 +00:00
|
|
|
const envelopePb = new SyncPb.MessageEnvelope();
|
|
|
|
envelopePb.setTimestamp(msg.timestamp);
|
|
|
|
envelopePb.setIsencrypted(msg.is_encrypted);
|
|
|
|
envelopePb.setContent(msg.content);
|
|
|
|
return envelopePb;
|
|
|
|
})
|
|
|
|
};
|
2022-03-31 17:19:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = { sync };
|