This commit is contained in:
team3
2026-09-19 21:37:34 +02:00
parent a5b92054dc
commit 736437f609
3 changed files with 44 additions and 6 deletions

View File

@@ -6,11 +6,13 @@ import {readJson, writeJson} from './store.js';
// Abgleich mit dem Server. Zugang steht in sync.json im Datenordner:
// {"url": "https://planer.marha.de", "token": "...", "interval": 5}
// Alle paar Sekunden: eigene Änderungen seit dem letzten Lauf hochladen, Änderungen des Servers
// seit dem letzten Stand holen. Bei Konflikten gewinnt der Eintrag mit dem neueren updated.
// Alle paar Sekunden und kurz nach jeder eigenen Änderung: eigene Änderungen hochladen,
// Änderungen des Servers seit dem letzten Stand holen. Bei Konflikten gewinnt der Eintrag mit dem neueren updated.
// sync-state.json merkt sich den Server-Stand (cursor) und was zuletzt übertragen wurde (pushed).
const DEFAULT_INTERVAL = 5;
// Kurze Wartezeit nach einer eigenen Änderung, damit mehrere Klicks in einem Lauf landen
const SOON_MS = 500;
export class Sync {
constructor(store) {
@@ -18,11 +20,18 @@ export class Sync {
this._config = readJson(GLib.build_filenamev([store.dir, 'sync.json']), null);
this._statePath = GLib.build_filenamev([store.dir, 'sync-state.json']);
this._state = readJson(this._statePath, {cursor: 0, pushed: {events: {}, todos: {}, notes: {}, folders: {}}});
this._state.pushed.folders ??= {};
// Ältere Stände kennen keine Ordner. Einmal alles neu holen, sonst fehlen Ordner,
// die der Server schon vor dem Update verteilt hat. Bekanntes wird dabei übersprungen.
if (!this._state.pushed.folders) {
this._state.pushed.folders = {};
this._state.cursor = 0;
}
this._session = new Soup.Session({timeout: 10});
this._busy = false;
this._failing = false;
this._timerId = null;
this._soonId = null;
this._applying = false;
}
get active() {
@@ -37,14 +46,30 @@ export class Sync {
this._cycle().catch(e => this._fail(e.message));
return GLib.SOURCE_CONTINUE;
});
// Eigene Änderungen gehen sofort raus, nicht erst beim nächsten Takt
this._store.onChange(() => this._scheduleSoon());
this._cycle().catch(e => this._fail(e.message));
}
_scheduleSoon() {
if (this._stopped || this._applying || this._soonId)
return;
this._soonId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, SOON_MS, () => {
this._soonId = null;
this._cycle().catch(e => this._fail(e.message));
return GLib.SOURCE_REMOVE;
});
}
stop() {
if (this._timerId) {
GLib.source_remove(this._timerId);
this._timerId = null;
}
if (this._soonId) {
GLib.source_remove(this._soonId);
this._soonId = null;
}
// Laufende Anfrage abbrechen, ohne das als Verbindungsfehler zu melden
this._stopped = true;
this._session.abort();
@@ -57,7 +82,13 @@ export class Sync {
try {
const payload = this._collect();
const response = await this._post(payload);
this._apply(response, payload);
// Übernommene Änderungen lösen selbst onChange aus, das soll keinen neuen Lauf starten
this._applying = true;
try {
this._apply(response, payload);
} finally {
this._applying = false;
}
if (this._failing) {
this._failing = false;
console.log('desktop-app sync: Verbindung wieder da');