server-ts: Port services/sync_update

This commit is contained in:
Elian Doran 2024-02-18 12:40:30 +02:00
parent 3ea4b7a72b
commit 0ba80b176c
No known key found for this signature in database
3 changed files with 46 additions and 23 deletions

View File

@ -1,7 +1,7 @@
"use strict"; "use strict";
const syncService = require('../../services/sync.js'); const syncService = require('../../services/sync.js');
const syncUpdateService = require('../../services/sync_update.js'); const syncUpdateService = require('../../services/sync_update');
const entityChangesService = require('../../services/entity_changes'); const entityChangesService = require('../../services/entity_changes');
const sql = require('../../services/sql'); const sql = require('../../services/sql');
const sqlInit = require('../../services/sql_init'); const sqlInit = require('../../services/sql_init');

View File

@ -6,7 +6,7 @@ const optionService = require('./options');
const utils = require('./utils'); const utils = require('./utils');
const instanceId = require('./instance_id'); const instanceId = require('./instance_id');
const dateUtils = require('./date_utils'); const dateUtils = require('./date_utils');
const syncUpdateService = require('./sync_update.js'); const syncUpdateService = require('./sync_update');
const contentHashService = require('./content_hash.js'); const contentHashService = require('./content_hash.js');
const appInfo = require('./app_info'); const appInfo = require('./app_info');
const syncOptions = require('./sync_options'); const syncOptions = require('./sync_options');

View File

@ -1,11 +1,28 @@
const sql = require('./sql'); import sql = require('./sql');
const log = require('./log'); import log = require('./log');
const entityChangesService = require('./entity_changes'); import entityChangesService = require('./entity_changes');
const eventService = require('./events'); import eventService = require('./events');
const entityConstructor = require('../becca/entity_constructor'); import entityConstructor = require('../becca/entity_constructor');
const ws = require('./ws'); import ws = require('./ws');
import { EntityChange } from './entity_changes_interface';
function updateEntities(entityChanges, instanceId) { interface EntityRow {
isDeleted?: boolean;
content: Buffer | string;
}
interface EntityChangeInput {
entityChange: EntityChange;
entity: EntityRow;
}
interface UpdateContext {
alreadyErased: number;
erased: number;
updated: Record<string, string[]>
}
function updateEntities(entityChanges: EntityChangeInput[], instanceId: string) {
if (entityChanges.length === 0) { if (entityChanges.length === 0) {
return; return;
} }
@ -40,7 +57,7 @@ function updateEntities(entityChanges, instanceId) {
logUpdateContext(updateContext); logUpdateContext(updateContext);
} }
function updateEntity(remoteEC, remoteEntityRow, instanceId, updateContext) { function updateEntity(remoteEC: EntityChange, remoteEntityRow: EntityRow, instanceId: string, updateContext: UpdateContext) {
if (!remoteEntityRow && remoteEC.entityName === 'options') { if (!remoteEntityRow && remoteEC.entityName === 'options') {
return; // can be undefined for options with isSynced=false return; // can be undefined for options with isSynced=false
} }
@ -65,8 +82,12 @@ function updateEntity(remoteEC, remoteEntityRow, instanceId, updateContext) {
} }
} }
function updateNormalEntity(remoteEC, remoteEntityRow, instanceId, updateContext) { function updateNormalEntity(remoteEC: EntityChange, remoteEntityRow: EntityRow, instanceId: string, updateContext: UpdateContext) {
const localEC = sql.getRow(`SELECT * FROM entity_changes WHERE entityName = ? AND entityId = ?`, [remoteEC.entityName, remoteEC.entityId]); const localEC = sql.getRow<EntityChange>(`SELECT * FROM entity_changes WHERE entityName = ? AND entityId = ?`, [remoteEC.entityName, remoteEC.entityId]);
if (!localEC.utcDateChanged || !remoteEC.utcDateChanged) {
throw new Error("Missing date changed.");
}
if (!localEC || localEC.utcDateChanged <= remoteEC.utcDateChanged) { if (!localEC || localEC.utcDateChanged <= remoteEC.utcDateChanged) {
if (remoteEC.isErased) { if (remoteEC.isErased) {
@ -110,28 +131,30 @@ function updateNormalEntity(remoteEC, remoteEntityRow, instanceId, updateContext
return false; return false;
} }
function preProcessContent(remoteEC, remoteEntityRow) { function preProcessContent(remoteEC: EntityChange, remoteEntityRow: EntityRow) {
if (remoteEC.entityName === 'blobs' && remoteEntityRow.content !== null) { 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 // 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 // "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) // is string note or note (syncs can arrive out of order)
remoteEntityRow.content = Buffer.from(remoteEntityRow.content, 'base64'); if (typeof remoteEntityRow.content === "string") {
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 // 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) // (possibly not a problem anymore with the newer better-sqlite3)
remoteEntityRow.content = ""; remoteEntityRow.content = "";
}
} }
} }
} }
function updateNoteReordering(remoteEC, remoteEntityRow, instanceId) { function updateNoteReordering(remoteEC: EntityChange, remoteEntityRow: EntityRow, instanceId: string) {
if (!remoteEntityRow) { if (!remoteEntityRow) {
throw new Error(`Empty note_reordering body for: ${JSON.stringify(remoteEC)}`); throw new Error(`Empty note_reordering body for: ${JSON.stringify(remoteEC)}`);
} }
for (const key in remoteEntityRow) { for (const key in remoteEntityRow) {
sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [remoteEntityRow[key], key]); sql.execute("UPDATE branches SET notePosition = ? WHERE branchId = ?", [remoteEntityRow[key as keyof EntityRow], key]);
} }
entityChangesService.putEntityChangeWithInstanceId(remoteEC, instanceId); entityChangesService.putEntityChangeWithInstanceId(remoteEC, instanceId);
@ -139,7 +162,7 @@ function updateNoteReordering(remoteEC, remoteEntityRow, instanceId) {
return true; return true;
} }
function eraseEntity(entityChange) { function eraseEntity(entityChange: EntityChange) {
const {entityName, entityId} = entityChange; const {entityName, entityId} = entityChange;
const entityNames = [ const entityNames = [
@ -161,7 +184,7 @@ function eraseEntity(entityChange) {
sql.execute(`DELETE FROM ${entityName} WHERE ${primaryKeyName} = ?`, [entityId]); sql.execute(`DELETE FROM ${entityName} WHERE ${primaryKeyName} = ?`, [entityId]);
} }
function logUpdateContext(updateContext) { function logUpdateContext(updateContext: UpdateContext) {
const message = JSON.stringify(updateContext) const message = JSON.stringify(updateContext)
.replaceAll('"', '') .replaceAll('"', '')
.replaceAll(":", ": ") .replaceAll(":", ": ")
@ -170,6 +193,6 @@ function logUpdateContext(updateContext) {
log.info(message.substr(1, message.length - 2)); log.info(message.substr(1, message.length - 2));
} }
module.exports = { export = {
updateEntities updateEntities
}; };