1
0
mirror of https://github.com/keeweb/keeweb.git synced 2024-06-29 08:00:53 +02:00

storage providers refactoring

This commit is contained in:
antelle 2016-03-27 10:06:23 +03:00
parent 9c9abaae80
commit aa200d3c88
9 changed files with 206 additions and 178 deletions

View File

@ -1,24 +1,18 @@
'use strict'; 'use strict';
var Launcher = require('../comp/launcher'), var Launcher = require('../comp/launcher');
AppSettingsModel = require('../models/app-settings-model');
var Storage = { var Storage = {
file: require('./storage-file'), file: new (require('./storage-file'))(),
dropbox: require('./storage-dropbox'), dropbox: new (require('./storage-dropbox'))(),
webdav: require('./storage-webdav'), webdav: new (require('./storage-webdav'))(),
gdrive: require('./storage-gdrive'), gdrive: new (require('./storage-gdrive'))(),
onedrive: require('./storage-onedrive'), onedrive: new (require('./storage-onedrive'))(),
cache: Launcher ? require('./storage-file-cache') : require('./storage-cache') cache: new (Launcher ? require('./storage-file-cache') : require('./storage-cache'))()
}; };
_.forEach(Storage, function(prv, name) { _.forEach(Storage, function(prv) {
if (!prv.system) { prv.init();
var enabled = AppSettingsModel.instance.get(name);
if (typeof enabled === 'boolean') {
prv.enabled = enabled;
}
}
}); });
module.exports = Storage; module.exports = Storage;

View File

@ -0,0 +1,37 @@
'use strict';
var Backbone = require('backbone'),
Logger = require('../util/logger'),
AppSettingsModel = require('../models/app-settings-model');
var StorageBase = function() {
};
_.extend(StorageBase.prototype, {
name: null,
icon: null,
iconSvg: null,
enabled: false,
system: false,
uipos: null,
logger: null,
appSettings: AppSettingsModel.instance,
init: function() {
if (!this.name) {
throw 'Failed to init provider: no name';
}
if (!this.system) {
var enabled = this.appSettings.get(this.name);
if (typeof enabled === 'boolean') {
this.enabled = enabled;
}
}
this.logger = new Logger('storage-' + this.name);
}
});
StorageBase.extend = Backbone.Model.extend;
module.exports = StorageBase;

View File

@ -1,11 +1,10 @@
'use strict'; 'use strict';
var Logger = require('../util/logger'); var StorageBase = require('./storage-base');
var logger = new Logger('storage-cache');
var idb = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB; var idb = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
var StorageCache = { var StorageCache = StorageBase.extend({
name: 'cache', name: 'cache',
enabled: !!idb, enabled: !!idb,
system: true, system: true,
@ -13,7 +12,7 @@ var StorageCache = {
db: null, db: null,
errorOpening: null, errorOpening: null,
init: function(callback) { initDb: function(callback) {
if (this.db) { if (this.db) {
return callback && callback(); return callback && callback();
} }
@ -21,7 +20,7 @@ var StorageCache = {
try { try {
var req = idb.open('FilesCache'); var req = idb.open('FilesCache');
req.onerror = function (e) { req.onerror = function (e) {
logger.error('Error opening indexed db', e); that.logger.error('Error opening indexed db', e);
that.errorOpening = e; that.errorOpening = e;
if (callback) { callback(e); } if (callback) { callback(e); }
}; };
@ -34,82 +33,85 @@ var StorageCache = {
db.createObjectStore('files'); db.createObjectStore('files');
}; };
} catch (e) { } catch (e) {
logger.error('Error opening indexed db', e); that.logger.error('Error opening indexed db', e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}, },
save: function(id, opts, data, callback) { save: function(id, opts, data, callback) {
logger.debug('Save', id); var that = this;
this.init((function(err) { that.logger.debug('Save', id);
that.initDb(function(err) {
if (err) { if (err) {
return callback && callback(err); return callback && callback(err);
} }
try { try {
var ts = logger.ts(); var ts = that.logger.ts();
var req = this.db.transaction(['files'], 'readwrite').objectStore('files').put(data, id); var req = that.db.transaction(['files'], 'readwrite').objectStore('files').put(data, id);
req.onsuccess = function () { req.onsuccess = function () {
logger.debug('Saved', id, logger.ts(ts)); that.logger.debug('Saved', id, that.logger.ts(ts));
if (callback) { callback(); } if (callback) { callback(); }
}; };
req.onerror = function () { req.onerror = function () {
logger.error('Error saving to cache', id, req.error); that.logger.error('Error saving to cache', id, req.error);
if (callback) { callback(req.error); } if (callback) { callback(req.error); }
}; };
} catch (e) { } catch (e) {
logger.error('Error saving to cache', id, e); that.logger.error('Error saving to cache', id, e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}).bind(this)); });
}, },
load: function(id, opts, callback) { load: function(id, opts, callback) {
logger.debug('Load', id); var that = this;
this.init((function(err) { that.logger.debug('Load', id);
that.initDb(function(err) {
if (err) { if (err) {
return callback && callback(err, null); return callback && callback(err, null);
} }
try { try {
var ts = logger.ts(); var ts = that.logger.ts();
var req = this.db.transaction(['files'], 'readonly').objectStore('files').get(id); var req = that.db.transaction(['files'], 'readonly').objectStore('files').get(id);
req.onsuccess = function () { req.onsuccess = function () {
logger.debug('Loaded', id, logger.ts(ts)); that.logger.debug('Loaded', id, that.logger.ts(ts));
if (callback) { callback(null, req.result); } if (callback) { callback(null, req.result); }
}; };
req.onerror = function () { req.onerror = function () {
logger.error('Error loading from cache', id, req.error); that.logger.error('Error loading from cache', id, req.error);
if (callback) { callback(req.error); } if (callback) { callback(req.error); }
}; };
} catch (e) { } catch (e) {
logger.error('Error loading from cache', id, e); that.logger.error('Error loading from cache', id, e);
if (callback) { callback(e, null); } if (callback) { callback(e, null); }
} }
}).bind(this)); });
}, },
remove: function(id, opts, callback) { remove: function(id, opts, callback) {
logger.debug('Remove', id); var that = this;
this.init((function(err) { that.logger.debug('Remove', id);
that.initDb(function(err) {
if (err) { if (err) {
return callback && callback(err); return callback && callback(err);
} }
try { try {
var ts = logger.ts(); var ts = that.logger.ts();
var req = this.db.transaction(['files'], 'readwrite').objectStore('files').delete(id); var req = that.db.transaction(['files'], 'readwrite').objectStore('files').delete(id);
req.onsuccess = function () { req.onsuccess = function () {
logger.debug('Removed', id, logger.ts(ts)); that.logger.debug('Removed', id, that.logger.ts(ts));
if (callback) { callback(); } if (callback) { callback(); }
}; };
req.onerror = function () { req.onerror = function () {
logger.error('Error removing from cache', id, req.error); that.logger.error('Error removing from cache', id, req.error);
if (callback) { callback(req.error); } if (callback) { callback(req.error); }
}; };
} catch(e) { } catch(e) {
logger.error('Error removing from cache', id, e); that.logger.error('Error removing from cache', id, e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}).bind(this)); });
} }
}; });
module.exports = StorageCache; module.exports = StorageCache;

View File

@ -1,14 +1,11 @@
'use strict'; 'use strict';
var DropboxLink = require('../comp/dropbox-link'), var StorageBase = require('./storage-base'),
AppSettingsModel = require('../models/app-settings-model'), DropboxLink = require('../comp/dropbox-link'),
Locale = require('../util/locale'), Locale = require('../util/locale'),
UrlUtils = require('../util/url-util'), UrlUtils = require('../util/url-util');
Logger = require('../util/logger');
var logger = new Logger('storage-dropbox'); var StorageDropbox = StorageBase.extend({
var StorageDropbox = {
name: 'dropbox', name: 'dropbox',
icon: 'dropbox', icon: 'dropbox',
enabled: true, enabled: true,
@ -28,7 +25,7 @@ var StorageDropbox = {
}, },
_toFullPath: function(path) { _toFullPath: function(path) {
var rootFolder = AppSettingsModel.instance.get('dropboxFolder'); var rootFolder = this.appSettings.get('dropboxFolder');
if (rootFolder) { if (rootFolder) {
path = UrlUtils.fixSlashes('/' + rootFolder + '/' + path); path = UrlUtils.fixSlashes('/' + rootFolder + '/' + path);
} }
@ -36,7 +33,7 @@ var StorageDropbox = {
}, },
_toRelPath: function(path) { _toRelPath: function(path) {
var rootFolder = AppSettingsModel.instance.get('dropboxFolder'); var rootFolder = this.appSettings.get('dropboxFolder');
if (rootFolder) { if (rootFolder) {
var ix = path.toLowerCase().indexOf(rootFolder.toLowerCase()); var ix = path.toLowerCase().indexOf(rootFolder.toLowerCase());
if (ix === 0) { if (ix === 0) {
@ -79,7 +76,7 @@ var StorageDropbox = {
var keyField = {id: 'key', title: 'dropboxAppKey', desc: 'dropboxAppKeyDesc', type: 'text', required: true, pattern: '\\w+', var keyField = {id: 'key', title: 'dropboxAppKey', desc: 'dropboxAppKeyDesc', type: 'text', required: true, pattern: '\\w+',
value: appKey}; value: appKey};
var folderField = {id: 'folder', title: 'dropboxFolder', desc: 'dropboxFolderSettingsDesc', type: 'text', var folderField = {id: 'folder', title: 'dropboxFolder', desc: 'dropboxFolderSettingsDesc', type: 'text',
value: AppSettingsModel.instance.get('dropboxFolder') || ''}; value: this.appSettings.get('dropboxFolder') || ''};
var canUseBuiltInKeys = DropboxLink.canUseBuiltInKeys(); var canUseBuiltInKeys = DropboxLink.canUseBuiltInKeys();
if (canUseBuiltInKeys) { if (canUseBuiltInKeys) {
fields.push(linkField); fields.push(linkField);
@ -106,7 +103,7 @@ var StorageDropbox = {
if (config.folder) { if (config.folder) {
config.folder = that._fixConfigFolder(config.folder); config.folder = that._fixConfigFolder(config.folder);
} }
AppSettingsModel.instance.set({ that.appSettings.set({
dropboxAppKey: config.key, dropboxAppKey: config.key,
dropboxFolder: config.folder dropboxFolder: config.folder
}); });
@ -145,7 +142,7 @@ var StorageDropbox = {
default: default:
return; return;
} }
AppSettingsModel.instance.set(key, value); this.appSettings.set(key, value);
}, },
getPathForName: function(fileName) { getPathForName: function(fileName) {
@ -153,39 +150,42 @@ var StorageDropbox = {
}, },
load: function(path, opts, callback) { load: function(path, opts, callback) {
logger.debug('Load', path); var that = this;
var ts = logger.ts(); that.logger.debug('Load', path);
path = this._toFullPath(path); var ts = that.logger.ts();
path = that._toFullPath(path);
DropboxLink.openFile(path, function(err, data, stat) { DropboxLink.openFile(path, function(err, data, stat) {
logger.debug('Loaded', path, stat ? stat.versionTag : null, logger.ts(ts)); that.logger.debug('Loaded', path, stat ? stat.versionTag : null, that.logger.ts(ts));
err = StorageDropbox._convertError(err); err = that._convertError(err);
if (callback) { callback(err, data, stat ? { rev: stat.versionTag } : null); } if (callback) { callback(err, data, stat ? { rev: stat.versionTag } : null); }
}, _.noop); }, _.noop);
}, },
stat: function(path, opts, callback) { stat: function(path, opts, callback) {
logger.debug('Stat', path); var that = this;
var ts = logger.ts(); that.logger.debug('Stat', path);
path = this._toFullPath(path); var ts = that.logger.ts();
path = that._toFullPath(path);
DropboxLink.stat(path, function(err, stat) { DropboxLink.stat(path, function(err, stat) {
if (stat && stat.isRemoved) { if (stat && stat.isRemoved) {
err = new Error('File removed'); err = new Error('File removed');
err.notFound = true; err.notFound = true;
} }
logger.debug('Stated', path, stat ? stat.versionTag : null, logger.ts(ts)); that.logger.debug('Stated', path, stat ? stat.versionTag : null, that.logger.ts(ts));
err = StorageDropbox._convertError(err); err = that._convertError(err);
if (callback) { callback(err, stat ? { rev: stat.versionTag } : null); } if (callback) { callback(err, stat ? { rev: stat.versionTag } : null); }
}, _.noop); }, _.noop);
}, },
save: function(path, opts, data, callback, rev) { save: function(path, opts, data, callback, rev) {
logger.debug('Save', path, rev); var that = this;
var ts = logger.ts(); that.logger.debug('Save', path, rev);
path = this._toFullPath(path); var ts = that.logger.ts();
path = that._toFullPath(path);
DropboxLink.saveFile(path, data, rev, function(err, stat) { DropboxLink.saveFile(path, data, rev, function(err, stat) {
logger.debug('Saved', path, logger.ts(ts)); that.logger.debug('Saved', path, that.logger.ts(ts));
if (!callback) { return; } if (!callback) { return; }
err = StorageDropbox._convertError(err); err = that._convertError(err);
callback(err, stat ? { rev: stat.versionTag } : null); callback(err, stat ? { rev: stat.versionTag } : null);
}, _.noop); }, _.noop);
}, },
@ -211,6 +211,6 @@ var StorageDropbox = {
}); });
}); });
} }
}; });
module.exports = StorageDropbox; module.exports = StorageDropbox;

View File

@ -1,11 +1,9 @@
'use strict'; 'use strict';
var Launcher = require('../comp/launcher'), var StorageBase = require('./storage-base'),
Logger = require('../util/logger'); Launcher = require('../comp/launcher');
var logger = new Logger('storage-file-cache'); var StorageFileCache = StorageBase.extend({
var StorageFileCache = {
name: 'cache', name: 'cache',
enabled: !!Launcher, enabled: !!Launcher,
system: true, system: true,
@ -16,7 +14,7 @@ var StorageFileCache = {
return Launcher.req('path').join(this.path, id); return Launcher.req('path').join(this.path, id);
}, },
init: function(callback) { initFs: function(callback) {
if (this.path) { if (this.path) {
return callback && callback(); return callback && callback();
} }
@ -29,67 +27,70 @@ var StorageFileCache = {
this.path = path; this.path = path;
callback(); callback();
} catch (e) { } catch (e) {
logger.error('Error opening local offline storage', e); this.logger.error('Error opening local offline storage', e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}, },
save: function(id, opts, data, callback) { save: function(id, opts, data, callback) {
logger.debug('Save', id); var that = this;
this.init((function(err) { that.logger.debug('Save', id);
that.initFs(function(err) {
if (err) { if (err) {
return callback && callback(err); return callback && callback(err);
} }
var ts = logger.ts(); var ts = logger.ts();
try { try {
Launcher.writeFile(this.getPath(id), data); Launcher.writeFile(that.getPath(id), data);
logger.debug('Saved', id, logger.ts(ts)); logger.debug('Saved', id, logger.ts(ts));
if (callback) { callback(); } if (callback) { callback(); }
} catch (e) { } catch (e) {
logger.error('Error saving to cache', id, e); logger.error('Error saving to cache', id, e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}).bind(this)); });
}, },
load: function(id, opts, callback) { load: function(id, opts, callback) {
logger.debug('Load', id); var that = this;
this.init((function(err) { that.logger.debug('Load', id);
that.initFs(function(err) {
if (err) { if (err) {
return callback && callback(null, err); return callback && callback(null, err);
} }
var ts = logger.ts(); var ts = that.logger.ts();
try { try {
var data = Launcher.readFile(this.getPath(id)); var data = Launcher.readFile(that.getPath(id));
logger.debug('Loaded', id, logger.ts(ts)); that.logger.debug('Loaded', id, that.logger.ts(ts));
if (callback) { callback(null, data.buffer); } if (callback) { callback(null, data.buffer); }
} catch (e) { } catch (e) {
logger.error('Error loading from cache', id, e); that.logger.error('Error loading from cache', id, e);
if (callback) { callback(e, null); } if (callback) { callback(e, null); }
} }
}).bind(this)); });
}, },
remove: function(id, opts, callback) { remove: function(id, opts, callback) {
logger.debug('Remove', id); var that = this;
this.init((function(err) { that.logger.debug('Remove', id);
that.initFs(function(err) {
if (err) { if (err) {
return callback && callback(err); return callback && callback(err);
} }
var ts = logger.ts(); var ts = that.logger.ts();
try { try {
var path = this.getPath(id); var path = that.getPath(id);
if (Launcher.fileExists(path)) { if (Launcher.fileExists(path)) {
Launcher.deleteFile(path); Launcher.deleteFile(path);
} }
logger.debug('Removed', id, logger.ts(ts)); that.logger.debug('Removed', id, that.logger.ts(ts));
if (callback) { callback(); } if (callback) { callback(); }
} catch(e) { } catch(e) {
logger.error('Error removing from cache', id, e); that.logger.error('Error removing from cache', id, e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}).bind(this)); });
} }
}; });
module.exports = StorageFileCache; module.exports = StorageFileCache;

View File

@ -1,41 +1,39 @@
'use strict'; 'use strict';
var Launcher = require('../comp/launcher'), var StorageBase = require('./storage-base'),
Logger = require('../util/logger'); Launcher = require('../comp/launcher');
var logger = new Logger('storage-file');
var fileWatchers = {}; var fileWatchers = {};
var StorageFile = { var StorageFile = StorageBase.extend({
name: 'file', name: 'file',
icon: 'hdd-o', icon: 'hdd-o',
enabled: !!Launcher, enabled: !!Launcher,
system: true, system: true,
load: function(path, opts, callback) { load: function(path, opts, callback) {
logger.debug('Load', path); this.logger.debug('Load', path);
var ts = logger.ts(); var ts = this.logger.ts();
try { try {
var data = Launcher.readFile(path); var data = Launcher.readFile(path);
var rev = Launcher.statFile(path).mtime.getTime().toString(); var rev = Launcher.statFile(path).mtime.getTime().toString();
logger.debug('Loaded', path, rev, logger.ts(ts)); this.logger.debug('Loaded', path, rev, this.logger.ts(ts));
if (callback) { callback(null, data.buffer, { rev: rev }); } if (callback) { callback(null, data.buffer, { rev: rev }); }
} catch (e) { } catch (e) {
logger.error('Error reading local file', path, e); this.logger.error('Error reading local file', path, e);
if (callback) { callback(e, null); } if (callback) { callback(e, null); }
} }
}, },
stat: function(path, opts, callback) { stat: function(path, opts, callback) {
logger.debug('Stat', path); this.logger.debug('Stat', path);
var ts = logger.ts(); var ts = this.logger.ts();
try { try {
var stat = Launcher.statFile(path); var stat = Launcher.statFile(path);
logger.debug('Stat done', path, logger.ts(ts)); this.logger.debug('Stat done', path, this.logger.ts(ts));
if (callback) { callback(null, { rev: stat.mtime.getTime().toString() }); } if (callback) { callback(null, { rev: stat.mtime.getTime().toString() }); }
} catch (e) { } catch (e) {
logger.error('Error stat local file', path, e); this.logger.error('Error stat local file', path, e);
if (e.code === 'ENOENT') { if (e.code === 'ENOENT') {
e.notFound = true; e.notFound = true;
} }
@ -44,15 +42,15 @@ var StorageFile = {
}, },
save: function(path, opts, data, callback, rev) { save: function(path, opts, data, callback, rev) {
logger.debug('Save', path, rev); this.logger.debug('Save', path, rev);
var ts = logger.ts(); var ts = this.logger.ts();
try { try {
if (rev) { if (rev) {
try { try {
var stat = Launcher.statFile(path); var stat = Launcher.statFile(path);
var fileRev = stat.mtime.getTime().toString(); var fileRev = stat.mtime.getTime().toString();
if (fileRev !== rev) { if (fileRev !== rev) {
logger.debug('Save mtime differs', rev, fileRev); this.logger.debug('Save mtime differs', rev, fileRev);
if (callback) { callback({ revConflict: true }, { rev: fileRev }); } if (callback) { callback({ revConflict: true }, { rev: fileRev }); }
return; return;
} }
@ -62,10 +60,10 @@ var StorageFile = {
} }
Launcher.writeFile(path, data); Launcher.writeFile(path, data);
var newRev = Launcher.statFile(path).mtime.getTime().toString(); var newRev = Launcher.statFile(path).mtime.getTime().toString();
logger.debug('Saved', path, logger.ts(ts)); this.logger.debug('Saved', path, this.logger.ts(ts));
if (callback) { callback(undefined, { rev: newRev }); } if (callback) { callback(undefined, { rev: newRev }); }
} catch (e) { } catch (e) {
logger.error('Error writing local file', path, e); this.logger.error('Error writing local file', path, e);
if (callback) { callback(e); } if (callback) { callback(e); }
} }
}, },
@ -73,7 +71,7 @@ var StorageFile = {
watch: function(path, callback) { watch: function(path, callback) {
var names = Launcher.parsePath(path); var names = Launcher.parsePath(path);
if (!fileWatchers[names.dir]) { if (!fileWatchers[names.dir]) {
logger.debug('Watch dir', names.dir); this.logger.debug('Watch dir', names.dir);
var fsWatcher = Launcher.createFsWatcher(names.dir); var fsWatcher = Launcher.createFsWatcher(names.dir);
fsWatcher.on('change', this.fsWatcherChange.bind(this, names.dir)); fsWatcher.on('change', this.fsWatcherChange.bind(this, names.dir));
fileWatchers[names.dir] = { fsWatcher: fsWatcher, callbacks: [] }; fileWatchers[names.dir] = { fsWatcher: fsWatcher, callbacks: [] };
@ -90,7 +88,7 @@ var StorageFile = {
watcher.callbacks.splice(ix, 1); watcher.callbacks.splice(ix, 1);
} }
if (!watcher.callbacks.length) { if (!watcher.callbacks.length) {
logger.debug('Stop watch dir', names.dir); this.logger.debug('Stop watch dir', names.dir);
watcher.fsWatcher.close(); watcher.fsWatcher.close();
delete fileWatchers[names.dir]; delete fileWatchers[names.dir];
} }
@ -99,15 +97,16 @@ var StorageFile = {
fsWatcherChange: function(dirname, evt, fileName) { fsWatcherChange: function(dirname, evt, fileName) {
var watcher = fileWatchers[dirname]; var watcher = fileWatchers[dirname];
var that = this;
if (watcher) { if (watcher) {
watcher.callbacks.forEach(function(cb) { watcher.callbacks.forEach(function(cb) {
if (cb.file === fileName && typeof cb.callback === 'function') { if (cb.file === fileName && typeof cb.callback === 'function') {
logger.debug('File changed', dirname, evt, fileName); that.logger.debug('File changed', dirname, evt, fileName);
cb.callback(); cb.callback();
} }
}); });
} }
} }
}; });
module.exports = StorageFile; module.exports = StorageFile;

View File

@ -1,12 +1,10 @@
'use strict'; 'use strict';
var Backbone = require('backbone'), var StorageBase = require('./storage-base'),
Logger = require('../util/logger'), Backbone = require('backbone'),
Timeouts = require('../const/timeouts'); Timeouts = require('../const/timeouts');
var logger = new Logger('storage-gdrive'); var StorageGDrive = StorageBase.extend({
var StorageGDrive = {
name: 'gdrive', name: 'gdrive',
icon: '', icon: '',
enabled: true, enabled: true,
@ -23,8 +21,8 @@ var StorageGDrive = {
var that = this; var that = this;
that.stat(path, opts, function(err, stat) { that.stat(path, opts, function(err, stat) {
if (err) { return callback && callback(err); } if (err) { return callback && callback(err); }
logger.debug('Load', path); that.logger.debug('Load', path);
var ts = logger.ts(); var ts = that.logger.ts();
var url = 'https://www.googleapis.com/drive/v3/files/{id}/revisions/{rev}?alt=media' var url = 'https://www.googleapis.com/drive/v3/files/{id}/revisions/{rev}?alt=media'
.replace('{id}', path) .replace('{id}', path)
.replace('{rev}', stat.rev); .replace('{rev}', stat.rev);
@ -32,14 +30,14 @@ var StorageGDrive = {
xhr.responseType = 'arraybuffer'; xhr.responseType = 'arraybuffer';
xhr.addEventListener('load', function() { xhr.addEventListener('load', function() {
if (xhr.status !== 200) { if (xhr.status !== 200) {
logger.debug('Load error', path, 'http status ' + xhr.status, logger.ts(ts)); that.logger.debug('Load error', path, 'http status ' + xhr.status, that.logger.ts(ts));
return callback && callback('load error ' + xhr.status); return callback && callback('load error ' + xhr.status);
} }
logger.debug('Loaded', path, stat.rev, logger.ts(ts)); that.logger.debug('Loaded', path, stat.rev, that.logger.ts(ts));
return callback && callback(null, xhr.response, { rev: stat.rev }); return callback && callback(null, xhr.response, { rev: stat.rev });
}); });
xhr.addEventListener('error', function() { xhr.addEventListener('error', function() {
logger.debug('Load error', path, logger.ts(ts)); that.logger.debug('Load error', path, that.logger.ts(ts));
return callback && callback('network error'); return callback && callback('network error');
}); });
xhr.open('GET', url); xhr.open('GET', url);
@ -54,17 +52,17 @@ var StorageGDrive = {
if (err) { if (err) {
return callback && callback(err); return callback && callback(err);
} }
logger.debug('Stat', path); that.logger.debug('Stat', path);
var ts = logger.ts(); var ts = that.logger.ts();
that._gapi.client.drive.files.get({ that._gapi.client.drive.files.get({
fileId: path, fileId: path,
fields: 'headRevisionId' fields: 'headRevisionId'
}).then(function (resp) { }).then(function (resp) {
var rev = resp.result.headRevisionId; var rev = resp.result.headRevisionId;
logger.debug('Stated', path, rev, logger.ts(ts)); that.logger.debug('Stated', path, rev, that.logger.ts(ts));
return callback && callback(null, { rev: rev }); return callback && callback(null, { rev: rev });
}, function(resp) { }, function(resp) {
logger.error('Stat error', logger.ts(ts), resp.result.error); that.logger.error('Stat error', that.logger.ts(ts), resp.result.error);
return callback && callback(resp.result.error.message || 'stat error'); return callback && callback(resp.result.error.message || 'stat error');
}); });
}); });
@ -79,8 +77,8 @@ var StorageGDrive = {
return callback && callback({revConflict: true}, stat); return callback && callback({revConflict: true}, stat);
} }
} }
logger.debug('Save', path); that.logger.debug('Save', path);
var ts = logger.ts(); var ts = that.logger.ts();
var url = 'https://www.googleapis.com/upload/drive/v3/files/{id}?uploadType=media&fields=headRevisionId' var url = 'https://www.googleapis.com/upload/drive/v3/files/{id}?uploadType=media&fields=headRevisionId'
.replace('{id}', path) .replace('{id}', path)
.replace('{rev}', stat.rev); .replace('{rev}', stat.rev);
@ -88,10 +86,10 @@ var StorageGDrive = {
xhr.responseType = 'json'; xhr.responseType = 'json';
xhr.addEventListener('load', function() { xhr.addEventListener('load', function() {
if (xhr.status !== 200) { if (xhr.status !== 200) {
logger.debug('Save error', path, 'http status ' + xhr.status, logger.ts(ts)); that.logger.debug('Save error', path, 'http status ' + xhr.status, that.logger.ts(ts));
return callback && callback('load error ' + xhr.status); return callback && callback('load error ' + xhr.status);
} }
logger.debug('Saved', path, logger.ts(ts)); that.logger.debug('Saved', path, that.logger.ts(ts));
var newRev = xhr.response.headRevisionId; var newRev = xhr.response.headRevisionId;
if (!newRev) { if (!newRev) {
return callback && callback('save error: no rev'); return callback && callback('save error: no rev');
@ -99,7 +97,7 @@ var StorageGDrive = {
return callback && callback(null, { rev: newRev }); return callback && callback(null, { rev: newRev });
}); });
xhr.addEventListener('error', function() { xhr.addEventListener('error', function() {
logger.debug('Save error', path, logger.ts(ts)); that.logger.debug('Save error', path, that.logger.ts(ts));
return callback && callback('network error'); return callback && callback('network error');
}); });
xhr.open('PATCH', url); xhr.open('PATCH', url);
@ -113,13 +111,13 @@ var StorageGDrive = {
var that = this; var that = this;
this._getClient(function(err) { this._getClient(function(err) {
if (err) { return callback && callback(err); } if (err) { return callback && callback(err); }
logger.debug('List'); that.logger.debug('List');
var ts = logger.ts(); var ts = that.logger.ts();
that._gapi.client.drive.files.list({ that._gapi.client.drive.files.list({
fields: 'files', fields: 'files',
q: 'fileExtension="kdbx" and mimeType="application/octet-stream" and trashed=false' q: 'fileExtension="kdbx" and mimeType="application/octet-stream" and trashed=false'
}).then(function(resp) { }).then(function(resp) {
logger.debug('Listed', logger.ts(ts)); that.logger.debug('Listed', that.logger.ts(ts));
if (!resp.result.files) { if (!resp.result.files) {
return callback && callback('list error'); return callback && callback('list error');
} }
@ -132,7 +130,7 @@ var StorageGDrive = {
}); });
return callback && callback(null, fileList); return callback && callback(null, fileList);
}, function(resp) { }, function(resp) {
logger.error('List error', logger.ts(ts), resp.result.error); that.logger.error('List error', that.logger.ts(ts), resp.result.error);
return callback && callback(resp.result.error.message || 'list error'); return callback && callback(resp.result.error.message || 'list error');
}); });
}); });
@ -150,34 +148,34 @@ var StorageGDrive = {
if (that._gapi) { if (that._gapi) {
that._loadDriveApi(that._authorize.bind(that, callback)); that._loadDriveApi(that._authorize.bind(that, callback));
} else { } else {
logger.debug('Loading gapi client'); that.logger.debug('Loading gapi client');
window.gApiClientLoaded = function() { window.gApiClientLoaded = function() {
if (that._gapiLoadTimeout) { if (that._gapiLoadTimeout) {
logger.debug('Loaded gapi client'); that.logger.debug('Loaded gapi client');
delete window.gDriveClientLoaded; delete window.gDriveClientLoaded;
that._gapi = window.gapi; that._gapi = window.gapi;
that._loadDriveApi(that._authorize.bind(that, callback)); that._loadDriveApi(that._authorize.bind(that, callback));
} }
}; };
$.getScript('https://apis.google.com/js/client.js?onload=gApiClientLoaded', function() { $.getScript('https://apis.google.com/js/client.js?onload=gApiClientLoaded', function() {
logger.debug('Loaded gapi script'); that.logger.debug('Loaded gapi script');
}).fail(function() { }).fail(function() {
logger.error('Failed to load gapi'); that.logger.error('Failed to load gapi');
return callback('gapi load failed'); return callback('gapi load failed');
}); });
} }
}, },
_loadDriveApi: function(callback) { _loadDriveApi: function(callback) {
logger.debug('Loading gdrive api');
var that = this; var that = this;
that.logger.debug('Loading gdrive api');
this._gapi.client.load('drive', 'v3', function(result) { this._gapi.client.load('drive', 'v3', function(result) {
if (that._gapiLoadTimeout) { if (that._gapiLoadTimeout) {
clearTimeout(that._gapiLoadTimeout); clearTimeout(that._gapiLoadTimeout);
delete that._gapiLoadTimeout; delete that._gapiLoadTimeout;
logger.debug('Loaded gdrive api'); that.logger.debug('Loaded gdrive api');
if (result && result.error) { if (result && result.error) {
logger.error('Error loading gdrive api', result.error); that.logger.error('Error loading gdrive api', result.error);
callback(result.error); callback(result.error);
} else { } else {
callback(); callback();
@ -196,25 +194,25 @@ var StorageGDrive = {
if (res && !res.error) { if (res && !res.error) {
callback(); callback();
} else { } else {
logger.debug('Authorizing...'); that.logger.debug('Authorizing...');
var handlePopupClosed = function() { var handlePopupClosed = function() {
logger.debug('Auth popup closed'); that.logger.debug('Auth popup closed');
Backbone.off('popup-closed', handlePopupClosed); Backbone.off('popup-closed', handlePopupClosed);
callback('popup closed'); callback('popup closed');
callback = null; callback = null;
}; };
Backbone.on('popup-closed', handlePopupClosed); Backbone.on('popup-closed', handlePopupClosed);
var ts = logger.ts(); var ts = that.logger.ts();
that._gapi.auth.authorize({'client_id': that._clientId, scope: scopes, immediate: false}, function(res) { that._gapi.auth.authorize({'client_id': that._clientId, scope: scopes, immediate: false}, function(res) {
if (!callback) { if (!callback) {
return; return;
} }
Backbone.off('popup-closed', handlePopupClosed); Backbone.off('popup-closed', handlePopupClosed);
if (res && !res.error) { if (res && !res.error) {
logger.debug('Authorized', logger.ts(ts)); that.logger.debug('Authorized', that.logger.ts(ts));
callback(); callback();
} else { } else {
logger.error('Authorize error', logger.ts(ts), res); that.logger.error('Authorize error', that.logger.ts(ts), res);
callback(res && res.error || 'authorize error'); callback(res && res.error || 'authorize error');
} }
}); });
@ -227,6 +225,6 @@ var StorageGDrive = {
var token = this._gapi.auth.getToken(); var token = this._gapi.auth.getToken();
return token.token_type + ' ' + token.access_token; return token.token_type + ' ' + token.access_token;
} }
}; });
module.exports = StorageGDrive; module.exports = StorageGDrive;

View File

@ -1,10 +1,8 @@
'use strict'; 'use strict';
//var Logger = require('../util/logger'); var StorageBase = require('./storage-base');
//var logger = new Logger('storage-onedrive'); var StorageOneDrive = StorageBase.extend({
var StorageOneDrive = {
name: 'onedrive', name: 'onedrive',
icon: '', icon: '',
enabled: false, enabled: false,
@ -33,6 +31,6 @@ var StorageOneDrive = {
save: function(path, opts, data, callback/*, rev*/) { save: function(path, opts, data, callback/*, rev*/) {
if (callback) { callback('not implemented'); } if (callback) { callback('not implemented'); }
} }
}; });
module.exports = StorageOneDrive; module.exports = StorageOneDrive;

View File

@ -1,10 +1,8 @@
'use strict'; 'use strict';
var Logger = require('../util/logger'); var StorageBase = require('./storage-base');
var logger = new Logger('storage-webdav'); var StorageWebDav = StorageBase.extend({
var StorageWebDav = {
name: 'webdav', name: 'webdav',
icon: 'server', icon: 'server',
enabled: true, enabled: true,
@ -67,7 +65,7 @@ var StorageWebDav = {
}, saveOpts), function(err, xhr, stat) { }, saveOpts), function(err, xhr, stat) {
if (err) { return cb(err); } if (err) { return cb(err); }
if (stat.rev !== rev) { if (stat.rev !== rev) {
logger.debug('Save error', path, 'rev conflict', stat.rev, rev); that.logger.debug('Save error', path, 'rev conflict', stat.rev, rev);
return cb({ revConflict: true }, xhr, stat); return cb({ revConflict: true }, xhr, stat);
} }
that._request(_.defaults({ that._request(_.defaults({
@ -82,7 +80,7 @@ var StorageWebDav = {
return cb(err, xhr, stat); return cb(err, xhr, stat);
} }
if (stat.rev !== rev) { if (stat.rev !== rev) {
logger.debug('Save error', path, 'rev conflict', stat.rev, rev); that.logger.debug('Save error', path, 'rev conflict', stat.rev, rev);
that._request(_.defaults({ op: 'Save:delete', method: 'DELETE', path: tmpPath }, saveOpts)); that._request(_.defaults({ op: 'Save:delete', method: 'DELETE', path: tmpPath }, saveOpts));
return cb({ revConflict: true }, xhr, stat); return cb({ revConflict: true }, xhr, stat);
} }
@ -131,16 +129,17 @@ var StorageWebDav = {
}, },
_request: function(config, callback) { _request: function(config, callback) {
var that = this;
if (config.rev) { if (config.rev) {
logger.debug(config.op, config.path, config.rev); that.logger.debug(config.op, config.path, config.rev);
} else { } else {
logger.debug(config.op, config.path); that.logger.debug(config.op, config.path);
} }
var ts = logger.ts(); var ts = that.logger.ts();
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.addEventListener('load', function() { xhr.addEventListener('load', function() {
if ([200, 201, 204].indexOf(xhr.status) < 0) { if ([200, 201, 204].indexOf(xhr.status) < 0) {
logger.debug(config.op + ' error', config.path, xhr.status, logger.ts(ts)); that.logger.debug(config.op + ' error', config.path, xhr.status, that.logger.ts(ts));
var err; var err;
switch (xhr.status) { switch (xhr.status) {
case 404: case 404:
@ -158,20 +157,20 @@ var StorageWebDav = {
} }
var rev = xhr.getResponseHeader('Last-Modified'); var rev = xhr.getResponseHeader('Last-Modified');
if (!rev && !config.nostat) { if (!rev && !config.nostat) {
logger.debug(config.op + ' error', config.path, 'no headers', logger.ts(ts)); that.logger.debug(config.op + ' error', config.path, 'no headers', that.logger.ts(ts));
if (callback) { callback('No Last-Modified header', xhr); callback = null; } if (callback) { callback('No Last-Modified header', xhr); callback = null; }
return; return;
} }
var completedOpName = config.op + (config.op.charAt(config.op.length - 1) === 'e' ? 'd' : 'ed'); var completedOpName = config.op + (config.op.charAt(config.op.length - 1) === 'e' ? 'd' : 'ed');
logger.debug(completedOpName, config.path, rev, logger.ts(ts)); that.logger.debug(completedOpName, config.path, rev, that.logger.ts(ts));
if (callback) { callback(null, xhr, rev ? { rev: rev } : null); callback = null; } if (callback) { callback(null, xhr, rev ? { rev: rev } : null); callback = null; }
}); });
xhr.addEventListener('error', function() { xhr.addEventListener('error', function() {
logger.debug(config.op + ' error', config.path, logger.ts(ts)); that.logger.debug(config.op + ' error', config.path, that.logger.ts(ts));
if (callback) { callback('network error', xhr); callback = null; } if (callback) { callback('network error', xhr); callback = null; }
}); });
xhr.addEventListener('abort', function() { xhr.addEventListener('abort', function() {
logger.debug(config.op + ' error', config.path, 'aborted', logger.ts(ts)); that.logger.debug(config.op + ' error', config.path, 'aborted', that.logger.ts(ts));
if (callback) { callback('aborted', xhr); callback = null; } if (callback) { callback('aborted', xhr); callback = null; }
}); });
xhr.responseType = 'arraybuffer'; xhr.responseType = 'arraybuffer';
@ -191,6 +190,6 @@ var StorageWebDav = {
xhr.send(); xhr.send();
} }
} }
}; });
module.exports = StorageWebDav; module.exports = StorageWebDav;