Notes/src/services/sync_update.js

117 lines
4.2 KiB
JavaScript
Raw Normal View History

2017-11-09 20:52:47 -05:00
const sql = require('./sql');
2021-02-11 22:50:32 +01:00
const log = require('./log');
2021-06-29 22:15:57 +02:00
const entityChangesService = require('./entity_changes');
2019-01-03 23:27:10 +01:00
const eventService = require('./events');
2021-06-29 22:15:57 +02:00
const entityConstructor = require("../becca/entity_constructor");
2017-11-09 20:52:47 -05:00
2023-07-29 21:59:20 +02:00
function updateEntity(remoteEC, remoteEntityRow, instanceId) {
if (!remoteEntityRow && remoteEC.entityName === 'options') {
return; // can be undefined for options with isSynced=false
2020-03-08 21:59:19 +01:00
}
2023-07-29 21:59:20 +02:00
const updated = remoteEC.entityName === 'note_reordering'
? updateNoteReordering(remoteEC, remoteEntityRow, instanceId)
: updateNormalEntity(remoteEC, remoteEntityRow, instanceId);
2019-01-03 23:27:10 +01:00
if (updated) {
2023-07-29 21:59:20 +02:00
if (remoteEntityRow?.isDeleted) {
2021-05-01 11:38:20 +02:00
eventService.emit(eventService.ENTITY_DELETE_SYNCED, {
2023-07-29 21:59:20 +02:00
entityName: remoteEC.entityName,
entityId: remoteEC.entityId
2021-05-01 11:38:20 +02:00
});
}
2023-07-29 21:59:20 +02:00
else if (!remoteEC.isErased) {
2021-05-01 11:38:20 +02:00
eventService.emit(eventService.ENTITY_CHANGE_SYNCED, {
2023-07-29 21:59:20 +02:00
entityName: remoteEC.entityName,
entityRow: remoteEntityRow
2021-05-01 11:38:20 +02:00
});
}
2019-01-03 23:27:10 +01:00
}
2018-04-07 22:25:28 -04:00
}
2023-07-29 21:59:20 +02:00
function updateNormalEntity(remoteEC, remoteEntityRow, instanceId) {
const localEC = sql.getRow(`SELECT * FROM entity_changes WHERE entityName = ? AND entityId = ?`, [remoteEC.entityName, remoteEC.entityId]);
2020-12-14 13:58:02 +01:00
2023-07-29 21:59:20 +02:00
if (!localEC?.isErased && remoteEC.isErased) {
eraseEntity(remoteEC, instanceId);
2020-12-14 13:58:02 +01:00
return true;
2023-07-29 21:59:20 +02:00
} else if (localEC?.isErased && !remoteEC.isErased) {
// on this side, we can't unerase the entity, so force the entity to be erased on the other side.
2023-07-29 23:25:02 +02:00
entityChangesService.putEntityChangeForOtherInstances(localEC);
2023-07-29 21:59:20 +02:00
2023-08-31 00:14:35 +02:00
return false;
} else if (localEC?.isErased && remoteEC.isErased) {
2023-07-29 21:59:20 +02:00
return false;
2020-12-14 13:58:02 +01:00
}
2023-07-29 21:59:20 +02:00
if (!localEC
|| localEC.utcDateChanged < remoteEC.utcDateChanged
|| (localEC.utcDateChanged === remoteEC.utcDateChanged && localEC.hash !== remoteEC.hash) // sync error, we should still update
2020-12-14 13:15:32 +01:00
) {
2023-07-29 21:59:20 +02:00
if (remoteEC.entityName === 'blobs' && remoteEntityRow.content !== null) {
2023-07-27 23:22:08 +02:00
// we always use a Buffer object which is different from normal saving - there we use a simple string type for
// "string notes". The problem is that in general, it's not possible to detect whether a blob content
// is string note or note (syncs can arrive out of order)
2023-07-29 21:59:20 +02:00
remoteEntityRow.content = Buffer.from(remoteEntityRow.content, 'base64');
2023-07-27 23:22:08 +02:00
2023-07-29 21:59:20 +02:00
if (remoteEntityRow.content.byteLength === 0) {
2023-07-27 23:22:08 +02:00
// there seems to be a bug which causes empty buffer to be stored as NULL which is then picked up as inconsistency
2023-07-29 21:59:20 +02:00
// (possibly not a problem anymore with the newer better-sqlite3)
2023-07-27 23:22:08 +02:00
remoteEntityRow.content = "";
}
}
2019-11-01 20:00:56 +01:00
2023-07-29 21:59:20 +02:00
sql.replace(remoteEC.entityName, remoteEntityRow);
2019-11-01 20:00:56 +01:00
2023-07-29 23:25:02 +02:00
entityChangesService.putEntityChangeWithInstanceId(remoteEC, instanceId);
2019-11-01 20:00:56 +01:00
return true;
2023-07-29 21:59:20 +02:00
} else if (localEC.hash !== remoteEC.hash && localEC.utcDateChanged > remoteEC.utcDateChanged) {
// the change on our side is newer than on the other side, so the other side should update
2023-07-29 23:25:02 +02:00
entityChangesService.putEntityChangeForOtherInstances(localEC);
2023-07-29 21:59:20 +02:00
return false;
}
return false;
2019-11-01 20:00:56 +01:00
}
2023-07-29 21:59:20 +02:00
function updateNoteReordering(remoteEC, remoteEntityRow, instanceId) {
for (const key in remoteEntityRow) {
sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [remoteEntityRow[key], key]);
}
2017-11-09 20:52:47 -05:00
2023-07-29 23:25:02 +02:00
entityChangesService.putEntityChangeWithInstanceId(remoteEC, instanceId);
return true;
2017-11-09 20:52:47 -05:00
}
2022-01-09 21:25:15 +01:00
function eraseEntity(entityChange, instanceId) {
const {entityName, entityId} = entityChange;
const entityNames = [
"notes",
"branches",
"attributes",
"revisions",
2023-03-16 12:17:55 +01:00
"attachments",
2023-07-29 21:59:20 +02:00
"blobs"
];
if (!entityNames.includes(entityName)) {
2023-07-29 21:59:20 +02:00
log.error(`Cannot erase entity '${entityName}', id '${entityId}'.`);
return;
}
2023-07-29 21:59:20 +02:00
const primaryKeyName = entityConstructor.getEntityFromEntityName(entityName).primaryKeyName;
2023-07-29 21:59:20 +02:00
sql.execute(`DELETE FROM ${entityName} WHERE ${primaryKeyName} = ?`, [entityId]);
2023-07-29 23:25:02 +02:00
entityChangesService.putEntityChangeWithInstanceId(entityChange, instanceId);
}
2017-11-09 20:52:47 -05:00
module.exports = {
2018-04-07 22:32:46 -04:00
updateEntity
2020-06-20 12:31:38 +02:00
};