mirror of
https://github.com/zadam/trilium.git
synced 2025-11-06 13:26:01 +01:00
sync fixes and refactorings
This commit is contained in:
@@ -4,98 +4,83 @@ const entityChangesService = require('./entity_changes');
|
||||
const eventService = require('./events');
|
||||
const entityConstructor = require("../becca/entity_constructor");
|
||||
|
||||
function updateEntity(entityChange, entityRow, instanceId) {
|
||||
// can be undefined for options with isSynced=false
|
||||
if (!entityRow) {
|
||||
if (entityChange.isSynced) {
|
||||
if (entityChange.isErased) {
|
||||
eraseEntity(entityChange, instanceId);
|
||||
}
|
||||
else {
|
||||
log.info(`Encountered synced non-erased entity change without entity: ${JSON.stringify(entityChange)}`);
|
||||
}
|
||||
}
|
||||
else if (entityChange.entityName !== 'options') {
|
||||
log.info(`Encountered unsynced non-option entity change without entity: ${JSON.stringify(entityChange)}`);
|
||||
}
|
||||
|
||||
return;
|
||||
function updateEntity(remoteEC, remoteEntityRow, instanceId) {
|
||||
if (!remoteEntityRow && remoteEC.entityName === 'options') {
|
||||
return; // can be undefined for options with isSynced=false
|
||||
}
|
||||
|
||||
const updated = entityChange.entityName === 'note_reordering'
|
||||
? updateNoteReordering(entityChange, entityRow, instanceId)
|
||||
: updateNormalEntity(entityChange, entityRow, instanceId);
|
||||
const updated = remoteEC.entityName === 'note_reordering'
|
||||
? updateNoteReordering(remoteEC, remoteEntityRow, instanceId)
|
||||
: updateNormalEntity(remoteEC, remoteEntityRow, instanceId);
|
||||
|
||||
if (updated) {
|
||||
if (entityRow.isDeleted) {
|
||||
if (remoteEntityRow?.isDeleted) {
|
||||
eventService.emit(eventService.ENTITY_DELETE_SYNCED, {
|
||||
entityName: entityChange.entityName,
|
||||
entityId: entityChange.entityId
|
||||
entityName: remoteEC.entityName,
|
||||
entityId: remoteEC.entityId
|
||||
});
|
||||
}
|
||||
else if (!entityChange.isErased) {
|
||||
else if (!remoteEC.isErased) {
|
||||
eventService.emit(eventService.ENTITY_CHANGE_SYNCED, {
|
||||
entityName: entityChange.entityName,
|
||||
entityRow
|
||||
entityName: remoteEC.entityName,
|
||||
entityRow: remoteEntityRow
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateNormalEntity(remoteEntityChange, remoteEntityRow, instanceId) {
|
||||
const localEntityChange = sql.getRow(`
|
||||
SELECT utcDateChanged, hash, isErased
|
||||
FROM entity_changes
|
||||
WHERE entityName = ? AND entityId = ?`, [remoteEntityChange.entityName, remoteEntityChange.entityId]);
|
||||
function updateNormalEntity(remoteEC, remoteEntityRow, instanceId) {
|
||||
const localEC = sql.getRow(`SELECT * FROM entity_changes WHERE entityName = ? AND entityId = ?`, [remoteEC.entityName, remoteEC.entityId]);
|
||||
|
||||
if (localEntityChange && !localEntityChange.isErased && remoteEntityChange.isErased) {
|
||||
sql.transactional(() => {
|
||||
const primaryKey = entityConstructor.getEntityFromEntityName(remoteEntityChange.entityName).primaryKeyName;
|
||||
|
||||
sql.execute(`DELETE FROM ${remoteEntityChange.entityName} WHERE ${primaryKey} = ?`, remoteEntityChange.entityId);
|
||||
|
||||
entityChangesService.addEntityChangeWithInstanceId(remoteEntityChange, instanceId);
|
||||
});
|
||||
if (!localEC?.isErased && remoteEC.isErased) {
|
||||
eraseEntity(remoteEC, instanceId);
|
||||
|
||||
return true;
|
||||
} 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.
|
||||
entityChangesService.addEntityChangeWithInstanceId(localEC, null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!localEntityChange
|
||||
|| localEntityChange.utcDateChanged < remoteEntityChange.utcDateChanged
|
||||
|| localEntityChange.hash !== remoteEntityChange.hash // sync error, we should still update
|
||||
if (!localEC
|
||||
|| localEC.utcDateChanged < remoteEC.utcDateChanged
|
||||
|| (localEC.utcDateChanged === remoteEC.utcDateChanged && localEC.hash !== remoteEC.hash) // sync error, we should still update
|
||||
) {
|
||||
if (remoteEntityChange.entityName === 'blobs') {
|
||||
if (remoteEC.entityName === 'blobs' && remoteEntityRow.content !== null) {
|
||||
// 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)
|
||||
remoteEntityRow.content = remoteEntityRow.content === null ? null : Buffer.from(remoteEntityRow.content, 'base64');
|
||||
remoteEntityRow.content = Buffer.from(remoteEntityRow.content, 'base64');
|
||||
|
||||
if (remoteEntityRow.content?.byteLength === 0) {
|
||||
if (remoteEntityRow.content.byteLength === 0) {
|
||||
// there seems to be a bug which causes empty buffer to be stored as NULL which is then picked up as inconsistency
|
||||
// (possibly not a problem anymore with the newer better-sqlite3)
|
||||
remoteEntityRow.content = "";
|
||||
}
|
||||
}
|
||||
|
||||
sql.transactional(() => {
|
||||
sql.replace(remoteEntityChange.entityName, remoteEntityRow);
|
||||
sql.replace(remoteEC.entityName, remoteEntityRow);
|
||||
|
||||
entityChangesService.addEntityChangeWithInstanceId(remoteEntityChange, instanceId);
|
||||
});
|
||||
entityChangesService.addEntityChangeWithInstanceId(remoteEC, instanceId);
|
||||
|
||||
return true;
|
||||
} 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
|
||||
entityChangesService.addEntityChangeWithInstanceId(localEC, null);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateNoteReordering(entityChange, entity, instanceId) {
|
||||
sql.transactional(() => {
|
||||
for (const key in entity) {
|
||||
sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [entity[key], key]);
|
||||
}
|
||||
function updateNoteReordering(remoteEC, remoteEntityRow, instanceId) {
|
||||
for (const key in remoteEntityRow) {
|
||||
sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [remoteEntityRow[key], key]);
|
||||
}
|
||||
|
||||
entityChangesService.addEntityChangeWithInstanceId(entityChange, instanceId);
|
||||
});
|
||||
entityChangesService.addEntityChangeWithInstanceId(remoteEC, instanceId);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -109,19 +94,17 @@ function eraseEntity(entityChange, instanceId) {
|
||||
"attributes",
|
||||
"revisions",
|
||||
"attachments",
|
||||
"blobs",
|
||||
"blobs"
|
||||
];
|
||||
|
||||
if (!entityNames.includes(entityName)) {
|
||||
log.error(`Cannot erase entity '${entityName}', id '${entityId}'`);
|
||||
log.error(`Cannot erase entity '${entityName}', id '${entityId}'.`);
|
||||
return;
|
||||
}
|
||||
|
||||
const keyName = entityConstructor.getEntityFromEntityName(entityName).primaryKeyName;
|
||||
const primaryKeyName = entityConstructor.getEntityFromEntityName(entityName).primaryKeyName;
|
||||
|
||||
sql.execute(`DELETE FROM ${entityName} WHERE ${keyName} = ?`, [entityId]);
|
||||
|
||||
eventService.emit(eventService.ENTITY_DELETE_SYNCED, { entityName, entityId });
|
||||
sql.execute(`DELETE FROM ${entityName} WHERE ${primaryKeyName} = ?`, [entityId]);
|
||||
|
||||
entityChangesService.addEntityChangeWithInstanceId(entityChange, instanceId);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user