From b24d06028139559cab955f58e71c0829fd240c25 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Wed, 9 Sep 2020 12:25:31 +0100 Subject: [PATCH] All: Got clock sync to work on mobile --- .../lib/file-api-driver-dropbox.js | 2 +- ReactNativeClient/lib/file-api.js | 34 ++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/ReactNativeClient/lib/file-api-driver-dropbox.js b/ReactNativeClient/lib/file-api-driver-dropbox.js index 876208821..f16c2dd33 100644 --- a/ReactNativeClient/lib/file-api-driver-dropbox.js +++ b/ReactNativeClient/lib/file-api-driver-dropbox.js @@ -44,7 +44,7 @@ class FileApiDriverDropbox { metadataToStat_(md, path) { const output = { path: path, - updated_time: md.server_modified ? new Date(md.server_modified) : new Date(), + updated_time: md.server_modified ? (new Date(md.server_modified)).getTime() : Date.now(), isDir: md['.tag'] === 'folder', }; diff --git a/ReactNativeClient/lib/file-api.js b/ReactNativeClient/lib/file-api.js index 52200673d..f188eac60 100644 --- a/ReactNativeClient/lib/file-api.js +++ b/ReactNativeClient/lib/file-api.js @@ -63,6 +63,31 @@ class FileApi { this.remoteDateMutex_ = new Mutex(); } + + async fetchRemoteDateOffset_() { + const tempFile = `${this.tempDirName()}/timeCheck${Math.round(Math.random() * 1000000)}.txt`; + const startTime = Date.now(); + await this.put(tempFile, 'timeCheck'); + + // Normally it should be possible to read the file back immediately but + // just in case, read it in a loop. + const loopStartTime = Date.now(); + let stat = null; + while (Date.now() - loopStartTime < 5000) { + stat = await this.stat(tempFile); + if (stat) break; + await time.msleep(200); + } + + if (!stat) throw new Error('Timed out trying to get sync target clock time'); + + this.delete(tempFile); // No need to await for this call + + const endTime = Date.now(); + const expectedTime = Math.round((endTime + startTime) / 2); + return stat.updated_time - expectedTime; + } + // Approximates the current time on the sync target. It caches the time offset to // improve performance. async remoteDate() { @@ -77,17 +102,10 @@ class FileApi { // Another call might have refreshed the time while we were waiting for the mutex, // so check again if we need to refresh. if (shouldSyncTime()) { - const tempFile = `${this.tempDirName()}/timeCheck${Math.random() * 10000}.txt`; - const startTime = Date.now(); - await this.put(tempFile, 'timeCheck'); - const stat = await this.stat(tempFile); - const endTime = Date.now(); - const expectedTime = Math.round((endTime + startTime) / 2); - this.remoteDateOffset_ = stat.updated_time.getTime() - expectedTime; + this.remoteDateOffset_ = await this.fetchRemoteDateOffset_(); // The sync target clock should rarely change but the device one might, // so we need to refresh relatively frequently. this.remoteDateNextCheckTime_ = Date.now() + 10 * 60 * 1000; - this.delete(tempFile); // No need to await for this call } } catch (error) { this.logger().warn('Could not retrieve remote date - defaulting to device date:', error);