From b6402cb17cfc87eff05e8b2fd42ad511ce5ef19e Mon Sep 17 00:00:00 2001 From: Val Packett Date: Fri, 26 Aug 2022 23:37:51 +0300 Subject: [PATCH] Plugin: use newest change time as lastSync instead of actual last sync request time This should be resilient against updates getting skipped due to timing issues, since this is what syncing "since time X" should actually mean. --- plugins/tiddlypwa/config.tid | 2 +- plugins/tiddlypwa/main.js | 40 ++++++++++++++++++------------- plugins/tiddlypwa/save-dialog.tid | 2 +- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/plugins/tiddlypwa/config.tid b/plugins/tiddlypwa/config.tid index 08868ef..391d49e 100644 --- a/plugins/tiddlypwa/config.tid +++ b/plugins/tiddlypwa/config.tid @@ -53,7 +53,7 @@ This device syncs wiki contents with the following servers: Server - Last successful sync + Last synced change diff --git a/plugins/tiddlypwa/main.js b/plugins/tiddlypwa/main.js index e0cabf6..e8087c4 100644 --- a/plugins/tiddlypwa/main.js +++ b/plugins/tiddlypwa/main.js @@ -538,10 +538,9 @@ Formatted with `deno fmt`. return; } this._saveTiddler(tiddler).then((_) => { - const now = new Date(); cb(null, '', 1); this.changesChannel.postMessage({ title: tiddler.fields.title }); - this.backgroundSync(now); + this.backgroundSync(); }).catch((e) => cb(e)); } @@ -581,10 +580,9 @@ Formatted with `deno fmt`. deleteTiddler(title, cb, _options) { this._deleteTiddler(title).then((_) => { - const now = new Date(); cb(null); this.changesChannel.postMessage({ title, del: true }); - this.backgroundSync(now); + this.backgroundSync(); }).catch((e) => cb(e)); } @@ -660,8 +658,8 @@ Formatted with `deno fmt`. } } - async _syncOneUnlocked({ url, token, lastSync = new Date(0) }, all = false, now = new Date()) { - this.logger.log('sync started', url, lastSync, all, now); + async _syncOneUnlocked({ url, token, lastSync = new Date(0) }, all = false) { + this.logger.log('sync started', url, lastSync, all); this.wiki.addTiddler({ title: '$:/status/TiddlyPWASyncingWith', text: url }); const changes = []; await new Promise((resolve) => @@ -678,8 +676,12 @@ Formatted with `deno fmt`. ); const clientChanges = []; const changedKeys = new Set(); + let newestChg = new Date(0); for (const { thash, title, tiv, data, iv, mtime, deleted } of changes) { if (arrayEq(thash, this.storyListHash)) continue; + if (mtime > newestChg) { + newestChg = mtime; + } const tidjson = { thash: await b64enc(thash), title: await b64enc(title), @@ -706,7 +708,7 @@ Formatted with `deno fmt`. token, browserToken: this.browserToken, authcode: await b64enc(await this.titlehash(token)), - now, + now: new Date(), // only for a desync check lastSync, clientChanges, }), @@ -748,6 +750,9 @@ Formatted with `deno fmt`. } else { titlesToRead.push({ title: tid.title, iv: tid.tiv }); } + if (tid.mtime > newestChg) { + newestChg = tid.mtime; + } } for (const title of $tw.wiki.allTitles()) { if (titleHashesToDelete.has(await b64enc(await this.titlehash(title)))) { @@ -772,11 +777,14 @@ Formatted with `deno fmt`. navigator.serviceWorker.controller.postMessage({ op: 'update', url: req.url }); } } - this.logger.log('sync done', url, now); - return now; + this.logger.log('sync done', url); + if (lastSync > newestChg) { + newestChg = lastSync; + } + return newestChg; } - async _syncManyUnlocked(all, now) { + async _syncManyUnlocked(all) { const servers = []; await new Promise((resolve) => this.db.transaction('syncservers').objectStore('syncservers').openCursor().onsuccess = (evt) => { @@ -790,7 +798,7 @@ Formatted with `deno fmt`. ); for (const [key, server] of servers) { try { - server.lastSync = await this._syncOneUnlocked(server, all, now); + server.lastSync = await this._syncOneUnlocked(server, all); await adb(this.db.transaction('syncservers', 'readwrite').objectStore('syncservers').put(server, key)); } catch (e) { if (e.name !== 'AbortError') { @@ -805,7 +813,7 @@ Formatted with `deno fmt`. this.isSyncing = false; } - sync(all, now) { + sync(all) { if (this.isSyncing) { return; } @@ -813,16 +821,16 @@ Formatted with `deno fmt`. this.wiki.addTiddler({ title: '$:/status/TiddlyPWASyncing', text: 'yes' }); if (!navigator.locks) { // welp, using multiple tabs without Web Locks is dangerous, but we can only YOLO it in this case - return this._syncManyUnlocked(all, now); + return this._syncManyUnlocked(all); } - return navigator.locks.request(`tiddlypwa:${location.pathname}`, (_lck) => this._syncManyUnlocked(all, now)); + return navigator.locks.request(`tiddlypwa:${location.pathname}`, (_lck) => this._syncManyUnlocked(all)); } - backgroundSync(now) { + backgroundSync() { if (!navigator.onLine) return; // debounced to handle multiple saves in quick succession clearTimeout(this.syncTimer); - this.syncTimer = setTimeout(() => this.sync(false, now), 1000); + this.syncTimer = setTimeout(() => this.sync(false), 1000); } } diff --git a/plugins/tiddlypwa/save-dialog.tid b/plugins/tiddlypwa/save-dialog.tid index ebd1a9a..bfcaaa4 100644 --- a/plugins/tiddlypwa/save-dialog.tid +++ b/plugins/tiddlypwa/save-dialog.tid @@ -6,7 +6,7 @@ title: $:/plugins/valpackett/tiddlypwa/save-dialog Server - Last successful sync + Last synced change <$list filter="[tag[$:/temp/TiddlyPWAServer]]">