From 9efbf74b6f93dcc099de27a828dc55afbc90246c Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Wed, 17 Jan 2018 21:01:41 +0000 Subject: [PATCH] All: Various changes to get filesystem target to work on mobile --- ReactNativeClient/lib/SyncTargetFilesystem.js | 5 +- .../lib/file-api-driver-local.js | 27 +++++---- ReactNativeClient/lib/fs-driver-node.js | 13 ++-- ReactNativeClient/lib/fs-driver-rn.js | 60 +++++++++++++++---- ReactNativeClient/lib/synchronizer.js | 4 +- ReactNativeClient/root.js | 6 ++ 6 files changed, 86 insertions(+), 29 deletions(-) diff --git a/ReactNativeClient/lib/SyncTargetFilesystem.js b/ReactNativeClient/lib/SyncTargetFilesystem.js index cf472a55e6..6dd4f4851e 100644 --- a/ReactNativeClient/lib/SyncTargetFilesystem.js +++ b/ReactNativeClient/lib/SyncTargetFilesystem.js @@ -24,9 +24,12 @@ class SyncTargetFilesystem extends BaseSyncTarget { } async initFileApi() { - const fileApi = new FileApi(Setting.value('sync.2.path'), new FileApiDriverLocal()); + const syncPath = Setting.value('sync.2.path'); + const driver = new FileApiDriverLocal(); + const fileApi = new FileApi(syncPath, driver); fileApi.setLogger(this.logger()); fileApi.setSyncTargetId(SyncTargetFilesystem.id()); + await driver.mkdir(syncPath); return fileApi; } diff --git a/ReactNativeClient/lib/file-api-driver-local.js b/ReactNativeClient/lib/file-api-driver-local.js index 611d15e955..754415ccf2 100644 --- a/ReactNativeClient/lib/file-api-driver-local.js +++ b/ReactNativeClient/lib/file-api-driver-local.js @@ -1,6 +1,3 @@ -const fs = require('fs-extra'); -const { promiseChain } = require('lib/promise-utils.js'); -const moment = require('moment'); const BaseItem = require('lib/models/BaseItem.js'); const { time } = require('lib/time-utils.js'); @@ -19,8 +16,9 @@ const { time } = require('lib/time-utils.js'); class FileApiDriverLocal { - fsErrorToJsError_(error) { + fsErrorToJsError_(error, path = null) { let msg = error.toString(); + if (path !== null) msg += '. Path: ' + path; let output = new Error(msg); if (error.code) output.code = error.code; return output; @@ -34,9 +32,9 @@ class FileApiDriverLocal { async stat(path) { try { const s = await this.fsDriver().stat(path); + if (!s) return null; return this.metadataFromStat_(s); } catch (error) { - if (error.code == 'ENOENT') return null; throw this.fsErrorToJsError_(error); } } @@ -106,7 +104,7 @@ class FileApiDriverLocal { items: output, }; } catch(error) { - throw this.fsErrorToJsError_(error); + throw this.fsErrorToJsError_(error, path); } } @@ -121,7 +119,7 @@ class FileApiDriverLocal { context: null, }; } catch(error) { - throw this.fsErrorToJsError_(error); + throw this.fsErrorToJsError_(error, path); } } @@ -138,19 +136,20 @@ class FileApiDriverLocal { } } catch (error) { if (error.code == 'ENOENT') return null; - throw this.fsErrorToJsError_(error); + throw this.fsErrorToJsError_(error, path); } return output; } async mkdir(path) { + console.info('EXISTST ' + path, await this.fsDriver().exists(path)); if (await this.fsDriver().exists(path)) return; try { await this.fsDriver().mkdir(path); } catch (error) { - throw this.fsErrorToJsError_(error); + throw this.fsErrorToJsError_(error, path); } // return new Promise((resolve, reject) => { @@ -182,7 +181,7 @@ class FileApiDriverLocal { await this.fsDriver().writeFile(path, content, 'utf8'); } catch (error) { - throw this.fsErrorToJsError_(error); + throw this.fsErrorToJsError_(error, path); } // if (!options) options = {}; @@ -204,7 +203,7 @@ class FileApiDriverLocal { try { await this.fsDriver().unlink(path); } catch (error) { - throw this.fsErrorToJsError_(error); + throw this.fsErrorToJsError_(error, path); } // return new Promise((resolve, reject) => { @@ -224,7 +223,11 @@ class FileApiDriverLocal { } async move(oldPath, newPath) { - return this.fsDriver().move(oldPath, newPath); + try { + await this.fsDriver().move(oldPath, newPath); + } catch (error) { + throw this.fsErrorToJsError_(error, path); + } // let lastError = null; diff --git a/ReactNativeClient/lib/fs-driver-node.js b/ReactNativeClient/lib/fs-driver-node.js index 7125b5482c..0f211b1c48 100644 --- a/ReactNativeClient/lib/fs-driver-node.js +++ b/ReactNativeClient/lib/fs-driver-node.js @@ -35,7 +35,7 @@ class FsDriverNode { await time.sleep(1); continue; } - throw this.fsErrorToJsError_(error); + throw error; } } @@ -51,9 +51,14 @@ class FsDriverNode { } async stat(path) { - const s = await fs.stat(path); - s.path = path; - return s; + try { + const s = await fs.stat(path); + s.path = path; + return s; + } catch (error) { + if (error.code == 'ENOENT') return null; + throw error; + } } async setTimestamp(path, timestampDate) { diff --git a/ReactNativeClient/lib/fs-driver-rn.js b/ReactNativeClient/lib/fs-driver-rn.js index ced34773d5..2b52293453 100644 --- a/ReactNativeClient/lib/fs-driver-rn.js +++ b/ReactNativeClient/lib/fs-driver-rn.js @@ -18,6 +18,38 @@ class FsDriverRN { throw new Error('Not implemented'); } + // Returns a format compatible with Node.js format + rnfsStatToStd_(stat, path) { + return { + birthtime: stat.ctime ? stat.ctime : stat.mtime, // Confusingly, "ctime" normally means "change time" but here it's used as "creation time". Also sometimes it is null + mtime: stat.mtime, + isDirectory: () => stat.isDirectory(), + path: path, + size: stat.size, + }; + } + + async readDirStats(path) { + let items = await RNFS.readDir(path); + let output = []; + for (let i = 0; i < items.length; i++) { + const item = items[i]; + console.info('ITEM', item); + const relativePath = item.path.substr(path.length + 1); + output.push(this.rnfsStatToStd_(item, relativePath)); + + // let stat = await this.stat(path + '/' + items[i]); + // if (!stat) continue; // Has been deleted between the readdir() call and now + // stat.path = stat.path.substr(path.length + 1); + // output.push(stat); + } + + console.info('READ DIR', path); + console.info(output); + + return output; + } + async move(source, dest) { return RNFS.moveFile(source, dest); } @@ -27,22 +59,30 @@ class FsDriverRN { } async mkdir(path) { - return fs.mkdir(path); + return RNFS.mkdir(path); } async stat(path) { - const r = await RNFS.stat(path); - // Returns a format compatible with Node.js format - return { - birthtime: r.ctime, // Confusingly, "ctime" normally means "change time" but here it's used as "creation time" - mtime: r.mtime, - isDirectory: () => r.isDirectory(), - path: path, - }; + try { + const r = await RNFS.stat(path); + return this.rnfsStatToStd_(r, path); + } catch (error) { + if (error && error.message && error.message.indexOf('exist') >= 0) { + // Probably { [Error: File does not exist] framesToPop: 1, code: 'EUNSPECIFIED' } + // which unfortunately does not have a proper error code. Can be ignored. + return null; + } else { + throw error; + } + } } + // NOTE: DOES NOT WORK - no error is thrown and the function is called with the right + // arguments but the function returns `false` and the timestamp is not set. + // Current setTimestamp is not really used so keep it that way, but careful if it + // becomes needed. async setTimestamp(path, timestampDate) { - return RNFS.touch(path, timestampDate); + // return RNFS.touch(path, timestampDate, timestampDate); } async open(path, mode) { diff --git a/ReactNativeClient/lib/synchronizer.js b/ReactNativeClient/lib/synchronizer.js index 2bea7b69fa..55574dde40 100644 --- a/ReactNativeClient/lib/synchronizer.js +++ b/ReactNativeClient/lib/synchronizer.js @@ -18,7 +18,7 @@ class Synchronizer { this.state_ = 'idle'; this.db_ = db; this.api_ = api; - this.syncDirName_ = '.sync'; + //this.syncDirName_ = '.sync'; this.resourceDirName_ = '.resource'; this.logger_ = new Logger(); this.appType_ = appType; @@ -197,7 +197,7 @@ class Synchronizer { this.logSyncOperation('starting', null, null, 'Starting synchronisation to target ' + syncTargetId + '... [' + synchronizationId + ']'); try { - await this.api().mkdir(this.syncDirName_); + //await this.api().mkdir(this.syncDirName_); await this.api().mkdir(this.resourceDirName_); let donePaths = []; diff --git a/ReactNativeClient/root.js b/ReactNativeClient/root.js index 16e29341f5..ee7fbd550b 100644 --- a/ReactNativeClient/root.js +++ b/ReactNativeClient/root.js @@ -44,14 +44,19 @@ const { _, setLocale, closestSupportedLocale, defaultLocale } = require('lib/loc const RNFetchBlob = require('react-native-fetch-blob').default; const { PoorManIntervals } = require('lib/poor-man-intervals.js'); const { reducer, defaultState } = require('lib/reducer.js'); +const { FileApiDriverLocal } = require('lib/file-api-driver-local.js'); const DropdownAlert = require('react-native-dropdownalert').default; const SyncTargetRegistry = require('lib/SyncTargetRegistry.js'); const SyncTargetOneDrive = require('lib/SyncTargetOneDrive.js'); +const SyncTargetFilesystem = require('lib/SyncTargetFilesystem.js'); const SyncTargetOneDriveDev = require('lib/SyncTargetOneDriveDev.js'); SyncTargetRegistry.addClass(SyncTargetOneDrive); SyncTargetRegistry.addClass(SyncTargetOneDriveDev); +// Disabled because not fully working +//SyncTargetRegistry.addClass(SyncTargetFilesystem); + const FsDriverRN = require('lib/fs-driver-rn.js').FsDriverRN; const DecryptionWorker = require('lib/services/DecryptionWorker'); const EncryptionService = require('lib/services/EncryptionService'); @@ -341,6 +346,7 @@ async function initialize(dispatch) { const fsDriver = new FsDriverRN(); Resource.fsDriver_ = fsDriver; + FileApiDriverLocal.fsDriver_ = fsDriver; AlarmService.setDriver(new AlarmServiceDriver()); AlarmService.setLogger(mainLogger);