Stefan Huber

last update

......@@ -4,21 +4,64 @@ Allows downloading of files referenced by a http/https URI inside a couchdb/pouc
# Usage
### In cordova projects
## Use it with pouchdb
### In electron projects
```typescript
import {ServiceLocator} from 'bsync-client/dist/browser-build';
Within the main process bsync needs to be integrated an initiated.
ServiceLocator.getConfig().setConfig('itemKey', 'type');
ServiceLocator.getConfig().setConfig('itemValue', 'asset');
import {Bsync} from 'bsync';
Bsync.init(ipcMain, filePath);
let localDb = new PouchDB('local-pouch-db');
let fileReplicator = ServiceLocator.getFileReplicator();
# Testing (Browser)
localDb.put({
_id : "_design/index_type",
views : {
type : {
map : function(doc) {
if (doc[fileReplicator.itemKey]) { emit(doc[fileReplicator.itemKey]); }
}.toString()
}
}
});
fileReplicator.once('complete', () => {
// All file are downloaded
});
db.query('index_type/type',{
include_docs : true,
key : fileReplicator.itemValue
}).then((res) => {
let docs = { docs : [] };
for (let r of res.rows) {
docs.docs.push(r.doc);
}
fileReplicator.pushChanges(docs);
fileReplicator.start();
});
```
## In electron projects
Within the `main process` bsync needs to be integrated an initiated.
```typescript
import {Bsync} from 'bsync';
Bsync.init(ipcMain, filePath);
```
# Testing (Browser/Node)
`npm test`
# Testing (Cordova)
`npm run test:cordova`
......
......@@ -8,10 +8,6 @@ export default {
format: 'umd',
globals: {
'rxjs' : 'Rx'
},
plugins: [
typescript() ,
globals(),
......
......@@ -9,13 +9,13 @@ export default {
entry: './src/browser-main.ts',
dest: './dist/browser-build.js',
format: 'cjs',
format: 'umd',
sourceMap: true ,
plugins: [
typescript(),
// globals(),
// builtins()
globals(),
builtins()
]
};
\ No newline at end of file
......
import typescript from 'rollup-plugin-typescript';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
export default {
......@@ -10,6 +12,8 @@ export default {
format: 'cjs',
plugins: [
typescript()
typescript(),
globals(),
builtins()
]
};
\ No newline at end of file
......
'use strict';
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.bsync = global.bsync || {})));
}(this, (function (exports) { 'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
var domain;
// This constructor is used to store event handlers. Instantiating this is
// faster than explicitly calling `Object.create(null)` to get a "clean" empty
// object (tested with v8 v4.9).
function EventHandlers() {}
EventHandlers.prototype = Object.create(null);
function EventEmitter() {
EventEmitter.init.call(this);
}
EventEmitter.usingDomains = false;
EventEmitter.prototype.domain = undefined;
EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;
// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;
EventEmitter.init = function() {
this.domain = null;
if (EventEmitter.usingDomains) {
// if there is an active domain, then attach to it.
if (domain.active && !(this instanceof domain.Domain)) {
this.domain = domain.active;
}
}
if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
this._events = new EventHandlers();
this._eventsCount = 0;
}
this._maxListeners = this._maxListeners || undefined;
};
// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
if (typeof n !== 'number' || n < 0 || isNaN(n))
throw new TypeError('"n" argument must be a positive number');
this._maxListeners = n;
return this;
};
function $getMaxListeners(that) {
if (that._maxListeners === undefined)
return EventEmitter.defaultMaxListeners;
return that._maxListeners;
}
EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
return $getMaxListeners(this);
};
// These standalone emit* functions are used to optimize calling of event
// handlers for fast cases because emit() itself often has a variable number of
// arguments and can be deoptimized because of that. These functions always have
// the same number of arguments and thus do not get deoptimized, so the code
// inside them can execute faster.
function emitNone(handler, isFn, self) {
if (isFn)
handler.call(self);
else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
listeners[i].call(self);
}
}
function emitOne(handler, isFn, self, arg1) {
if (isFn)
handler.call(self, arg1);
else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
listeners[i].call(self, arg1);
}
}
function emitTwo(handler, isFn, self, arg1, arg2) {
if (isFn)
handler.call(self, arg1, arg2);
else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
listeners[i].call(self, arg1, arg2);
}
}
function emitThree(handler, isFn, self, arg1, arg2, arg3) {
if (isFn)
handler.call(self, arg1, arg2, arg3);
else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
listeners[i].call(self, arg1, arg2, arg3);
}
}
function emitMany(handler, isFn, self, args) {
if (isFn)
handler.apply(self, args);
else {
var len = handler.length;
var listeners = arrayClone(handler, len);
for (var i = 0; i < len; ++i)
listeners[i].apply(self, args);
}
}
EventEmitter.prototype.emit = function emit(type) {
var er, handler, len, args, i, events, domain;
var needDomainExit = false;
var doError = (type === 'error');
events = this._events;
if (events)
doError = (doError && events.error == null);
else if (!doError)
return false;
domain = this.domain;
// If there is no 'error' event listener then throw.
if (doError) {
er = arguments[1];
if (domain) {
if (!er)
er = new Error('Uncaught, unspecified "error" event');
er.domainEmitter = this;
er.domain = domain;
er.domainThrown = false;
domain.emit('error', er);
} else if (er instanceof Error) {
throw er; // Unhandled 'error' event
} else {
// At least give some kind of context to the user
var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
err.context = er;
throw err;
}
return false;
}
handler = events[type];
if (!handler)
return false;
var isFn = typeof handler === 'function';
len = arguments.length;
switch (len) {
// fast cases
case 1:
emitNone(handler, isFn, this);
break;
case 2:
emitOne(handler, isFn, this, arguments[1]);
break;
case 3:
emitTwo(handler, isFn, this, arguments[1], arguments[2]);
break;
case 4:
emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
break;
// slower
default:
args = new Array(len - 1);
for (i = 1; i < len; i++)
args[i - 1] = arguments[i];
emitMany(handler, isFn, this, args);
}
if (needDomainExit)
domain.exit();
return true;
};
function _addListener(target, type, listener, prepend) {
var m;
var events;
var existing;
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
events = target._events;
if (!events) {
events = target._events = new EventHandlers();
target._eventsCount = 0;
} else {
// To avoid recursion in the case that type === "newListener"! Before
// adding it to the listeners, first emit "newListener".
if (events.newListener) {
target.emit('newListener', type,
listener.listener ? listener.listener : listener);
// Re-assign `events` because a newListener handler could have caused the
// this._events to be assigned to a new object
events = target._events;
}
existing = events[type];
}
var events = require('events');
var rxjs = require('rxjs');
if (!existing) {
// Optimize the case of one listener. Don't need the extra array object.
existing = events[type] = listener;
++target._eventsCount;
} else {
if (typeof existing === 'function') {
// Adding the second element, need to change to array.
existing = events[type] = prepend ? [listener, existing] :
[existing, listener];
} else {
// If we've already got an array, just append.
if (prepend) {
existing.unshift(listener);
} else {
existing.push(listener);
}
}
// Check for listener leak
if (!existing.warned) {
m = $getMaxListeners(target);
if (m && m > 0 && existing.length > m) {
existing.warned = true;
var w = new Error('Possible EventEmitter memory leak detected. ' +
existing.length + ' ' + type + ' listeners added. ' +
'Use emitter.setMaxListeners() to increase limit');
w.name = 'MaxListenersExceededWarning';
w.emitter = target;
w.type = type;
w.count = existing.length;
emitWarning(w);
}
}
}
return target;
}
function emitWarning(e) {
typeof console.warn === 'function' ? console.warn(e) : console.log(e);
}
EventEmitter.prototype.addListener = function addListener(type, listener) {
return _addListener(this, type, listener, false);
};
EventEmitter.prototype.on = EventEmitter.prototype.addListener;
EventEmitter.prototype.prependListener =
function prependListener(type, listener) {
return _addListener(this, type, listener, true);
};
function _onceWrap(target, type, listener) {
var fired = false;
function g() {
target.removeListener(type, g);
if (!fired) {
fired = true;
listener.apply(target, arguments);
}
}
g.listener = listener;
return g;
}
EventEmitter.prototype.once = function once(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.on(type, _onceWrap(this, type, listener));
return this;
};
EventEmitter.prototype.prependOnceListener =
function prependOnceListener(type, listener) {
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
this.prependListener(type, _onceWrap(this, type, listener));
return this;
};
// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener =
function removeListener(type, listener) {
var list, events, position, i, originalListener;
if (typeof listener !== 'function')
throw new TypeError('"listener" argument must be a function');
events = this._events;
if (!events)
return this;
list = events[type];
if (!list)
return this;
if (list === listener || (list.listener && list.listener === listener)) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else {
delete events[type];
if (events.removeListener)
this.emit('removeListener', type, list.listener || listener);
}
} else if (typeof list !== 'function') {
position = -1;
for (i = list.length; i-- > 0;) {
if (list[i] === listener ||
(list[i].listener && list[i].listener === listener)) {
originalListener = list[i].listener;
position = i;
break;
}
}
if (position < 0)
return this;
if (list.length === 1) {
list[0] = undefined;
if (--this._eventsCount === 0) {
this._events = new EventHandlers();
return this;
} else {
delete events[type];
}
} else {
spliceOne(list, position);
}
if (events.removeListener)
this.emit('removeListener', type, originalListener || listener);
}
return this;
};
EventEmitter.prototype.removeAllListeners =
function removeAllListeners(type) {
var listeners, events;
events = this._events;
if (!events)
return this;
// not listening for removeListener, no need to emit
if (!events.removeListener) {
if (arguments.length === 0) {
this._events = new EventHandlers();
this._eventsCount = 0;
} else if (events[type]) {
if (--this._eventsCount === 0)
this._events = new EventHandlers();
else
delete events[type];
}
return this;
}
// emit removeListener for all listeners on all events
if (arguments.length === 0) {
var keys = Object.keys(events);
for (var i = 0, key; i < keys.length; ++i) {
key = keys[i];
if (key === 'removeListener') continue;
this.removeAllListeners(key);
}
this.removeAllListeners('removeListener');
this._events = new EventHandlers();
this._eventsCount = 0;
return this;
}
listeners = events[type];
if (typeof listeners === 'function') {
this.removeListener(type, listeners);
} else if (listeners) {
// LIFO order
do {
this.removeListener(type, listeners[listeners.length - 1]);
} while (listeners[0]);
}
return this;
};
EventEmitter.prototype.listeners = function listeners(type) {
var evlistener;
var ret;
var events = this._events;
if (!events)
ret = [];
else {
evlistener = events[type];
if (!evlistener)
ret = [];
else if (typeof evlistener === 'function')
ret = [evlistener.listener || evlistener];
else
ret = unwrapListeners(evlistener);
}
return ret;
};
EventEmitter.listenerCount = function(emitter, type) {
if (typeof emitter.listenerCount === 'function') {
return emitter.listenerCount(type);
} else {
return listenerCount.call(emitter, type);
}
};
EventEmitter.prototype.listenerCount = listenerCount;
function listenerCount(type) {
var events = this._events;
if (events) {
var evlistener = events[type];
if (typeof evlistener === 'function') {
return 1;
} else if (evlistener) {
return evlistener.length;
}
}
return 0;
}
EventEmitter.prototype.eventNames = function eventNames() {
return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
};
// About 1.5x faster than the two-arg version of Array#splice().
function spliceOne(list, index) {
for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
list[i] = list[k];
list.pop();
}
function arrayClone(arr, i) {
var copy = new Array(i);
while (i--)
copy[i] = arr[i];
return copy;
}
function unwrapListeners(arr) {
var ret = new Array(arr.length);
for (var i = 0; i < ret.length; ++i) {
ret[i] = arr[i].listener || arr[i];
}
return ret;
}
function __extends(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
......@@ -11,68 +477,168 @@ function __extends(d, b) {
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var ElectronFileHandler = (function () {
var ElectronFileHandler = (function (_super) {
__extends(ElectronFileHandler, _super);
function ElectronFileHandler(ipcRenderer) {
_super.call(this);
this.ipcRenderer = ipcRenderer;
}
ElectronFileHandler.prototype.download = function (source, target) {
var _this = this;
return rxjs.Observable.create(function (subscriber) {
_this.ipcRenderer.once('bsync-download-complete', function () {
this.ipcRenderer.once('bsync-download-complete', function () {
_this.ipcRenderer.removeAllListeners('bsync-download-progress');
_this.ipcRenderer.removeAllListeners('bsync-download-error');
subscriber.complete();
_this.emit('complete');
});
_this.ipcRenderer.on('bsync-download-progress', function (progress) {
subscriber.next(progress);
this.ipcRenderer.on('bsync-download-progress', function (progress) {
_this.emit('progress', progress);
});
_this.ipcRenderer.once('bsync-download-error', function (error) {
this.ipcRenderer.once('bsync-download-error', function (error) {
_this.ipcRenderer.removeAllListeners('bsync-download-progress');
_this.ipcRenderer.removeAllListeners('bsync-download-complete');
subscriber.error(error);
_this.emit('error', error);
});
_this.ipcRenderer.send('bsync-download', {
this.ipcRenderer.send('bsync-download', {
source: source,
target: target
});
return this;
};
ElectronFileHandler.prototype.cleanup = function (files) {
var _this = this;
return new Promise(function (resolve, reject) {
_this.ipcRenderer.once('bsync-cleanup-complete', function () {
_this.emit('cleanup-complete');
resolve();
});
_this.ipcRenderer.send('bsync-cleanup', files);
});
};
return ElectronFileHandler;
}());
}(EventEmitter));
var CordovaDownloader = (function () {
function CordovaDownloader() {
var Util = (function () {
function Util() {
}
CordovaDownloader.prototype.download = function (source, target) {
return Rx.Observable.create(function (subscriber) {
if (!window['FileTransfer']) {
subscriber.error("Cordova FileTransfer object undefined");
Util.getNameHash = function (path) {
for (var r = 0, i = 0; i < path.length; i++) {
r = (r << 5) - r + path.charCodeAt(i), r &= r;
}
return "bsync_" + Math.abs(r);
};
/**
* index >= 0, localFile is in files
* index < 0, localFile is not in files
*/
Util.getFileIndex = function (files, localFile) {
for (var i = 0; i < files.length; i++) {
if (localFile == files[i].target) {
return i;
}
}
return -1;
};
Util.getFilesForCleanup = function (files, localFiles) {
var filesForCleanup = [];
for (var _i = 0, localFiles_1 = localFiles; _i < localFiles_1.length; _i++) {
var localFile = localFiles_1[_i];
var index = -1;
index = Util.getFileIndex(files, localFile);
if (index < 0) {
filesForCleanup.push(localFile);
}
else {
// splice for performance improvement only
files.splice(index, 1);
}
}
return filesForCleanup;
};
return Util;
}());
var CordovaFileHandler = (function (_super) {
__extends(CordovaFileHandler, _super);
function CordovaFileHandler() {
_super.apply(this, arguments);
}
CordovaFileHandler.prototype.triggerFileTransfer = function (source, target) {
var _this = this;
var fileTransfer = new window['FileTransfer']();
fileTransfer.onprogress = function (progress) {
subscriber.next(progress.loaded / progress.total);
_this.emit('progress', progress.loaded / progress.total);
};
fileTransfer.download(source, target, function (entry) {
subscriber.complete();
_this.emit('complete', entry);
}, function (error) {
subscriber.error(error);
_this.emit('error', error);
}, true);
};
CordovaFileHandler.prototype.download = function (source, target) {
var _this = this;
if (!window['FileTransfer']) {
this.emit('error', 'Cordova FileTransfer object undefined');
}
window['resolveLocalFileSystemURL'](target, function (entry) {
entry.getMetadata(function (metadata) {
if (metadata.size > 0) {
_this.emit('complete', entry);
}
else {
// file empty trigger transfer
_this.triggerFileTransfer(source, target);
}
}, function () {
// cannot read metadata trigger transfer
_this.triggerFileTransfer(source, target);
});
}, function () {
// file not found, so download it
_this.triggerFileTransfer(source, target);
});
return this;
};
return CordovaDownloader;
}());
var Util = (function () {
function Util() {
CordovaFileHandler.prototype.cleanup = function (files, basePath) {
var _this = this;
var filesForCleanup = [];
return new Promise(function (resolve, reject) {
if (window['resolveLocalFileSystemURL']) {
window['resolveLocalFileSystemURL'](basePath, function (entry) {
var reader = entry.createReader();
reader.readEntries(function (entries) {
for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
var e = entries_1[_i];
if (e && e.isFile) {
if (Util.getFileIndex(files, e.name) < 0) {
filesForCleanup.push(e);
}
}
}
var index = 0;
var error = false;
var cleanupError = function (error) {
_this.emit('cleanup-error', error);
reject();
error = true;
};
var cleanupNext = function () {
if (index < filesForCleanup.length && !error) {
filesForCleanup[index].remove(cleanupNext, cleanupError);
index += 1;
}
Util.getNameHash = function (path) {
for (var r = 0, i = 0; i < path.length; i++) {
r = (r << 5) - r + path.charCodeAt(i), r &= r;
else if (!error) {
_this.emit('cleanup-complete', filesForCleanup);
resolve();
}
return "bsync_" + Math.abs(r);
};
return Util;
}());
cleanupNext();
}, function (error) { _this.emit('cleanup-error', error); reject(); });
});
}
});
};
return CordovaFileHandler;
}(EventEmitter));
var FileReplicator = (function (_super) {
__extends(FileReplicator, _super);
......@@ -81,11 +647,13 @@ var FileReplicator = (function (_super) {
this._files = [];
this._itemValidator = null;
this._fileHandler = null;
this._retryTimeout = 0;
this._retryTimeout = 100;
this._retries = 10;
this._itemKey = "type";
this._itemValue = "asset";
this._itemSourceAttribute = "source";
this._itemTargetAttribute = "target";
this._targetDirectory = "";
}
Object.defineProperty(FileReplicator.prototype, "files", {
get: function () {
......@@ -95,6 +663,9 @@ var FileReplicator = (function (_super) {
configurable: true
});
Object.defineProperty(FileReplicator.prototype, "fileHandler", {
get: function () {
return this._fileHandler;
},
set: function (handler) {
this._fileHandler = handler;
},
......@@ -155,26 +726,36 @@ var FileReplicator = (function (_super) {
enumerable: true,
configurable: true
});
FileReplicator.prototype.init = function (files) {
Object.defineProperty(FileReplicator.prototype, "targetDirectory", {
get: function () {
return this._targetDirectory;
},
set: function (targetDirectory) {
this._targetDirectory = targetDirectory;
},
enumerable: true,
configurable: true
});
FileReplicator.prototype.clear = function (files) {
if (files === void 0) { files = []; }
this._files = files;
};
/**
* change from pouchdb replicate
*/
FileReplicator.prototype.pushChanges = function (change) {
FileReplicator.prototype.pushChanges = function (docs) {
var items = [];
if (change && change.docs && change.docs.length > 0) {
for (var _i = 0, _a = change.docs; _i < _a.length; _i++) {
var item = _a[_i];
if (docs && docs.length > 0) {
for (var _i = 0, docs_1 = docs; _i < docs_1.length; _i++) {
var item = docs_1[_i];
if (item[this._itemKey] && item[this._itemKey] === this._itemValue) {
items.push(item);
}
}
}
var files = this.prepareFiles(items);
for (var _b = 0, files_1 = files; _b < files_1.length; _b++) {
var file = files_1[_b];
for (var _a = 0, files_1 = files; _a < files_1.length; _a++) {
var file = files_1[_a];
this._files.push(file);
}
};
......@@ -186,15 +767,19 @@ var FileReplicator = (function (_super) {
}
this.emit('start', { progress: 0, index: index, length: files.length });
fileHandler
.download(files[index].source, files[index].target)
.subscribe(function (progress) {
_this.emit('progress', { progress: progress, index: index, length: files.length });
}, function (error) {
_this.emit('error', { progress: 0, index: index, length: files.length, error: error });
}, function () {
_this.emit('complete', { progress: 100, index: index, length: files.length });
.on('progress', function (progress) {
_this.emit('file-progress', { progress: progress, index: index, length: files.length });
})
.once('error', function (error) {
_this.emit('file-error', { progress: 0, index: index, length: files.length, error: error });
fileHandler.removeAllListeners();
})
.once('complete', function () {
_this.emit('file-complete', { progress: 100, index: index, length: files.length });
fileHandler.removeAllListeners();
_this.downloadFiles(files, fileHandler, index + 1);
});
})
.download(files[index].source, this.targetDirectory + files[index].target);
};
FileReplicator.prototype.prepareFiles = function (items) {
var output = [];
......@@ -213,41 +798,62 @@ var FileReplicator = (function (_super) {
}
return output;
};
FileReplicator.prototype.start = function () {
FileReplicator.prototype.start = function (retries) {
var _this = this;
this.on('complete', function (event) {
if (retries === void 0) { retries = 10; }
this._retries = retries;
this.on('file-complete', function (event) {
if ((event.index + 1) >= event.length) {
_this.replicationFinalized(event.index);
}
});
this.on('error', function (event) {
this.on('file-error', function (event) {
_this.replicationFinalized(event.index);
});
if (this._fileHandler && this._files.length > 0) {
this.downloadFiles(this._files, this._fileHandler);
}
else {
this.emit('complete');
}
};
FileReplicator.prototype.cleanup = function () {
var _this = this;
this.fileHandler
.cleanup(this._files, this._targetDirectory)
.then(function () {
_this.emit('cleanup-complete');
}).catch(function () {
_this.emit('cleanup-error');
});
};
FileReplicator.prototype.replicationFinalized = function (lastIndex) {
var _this = this;
if (lastIndex + 1 >= this._files.length) {
this._files = [];
this.emit('final');
this.emit('complete');
}
else if (this._retryTimeout > 0) {
else if (this._retries > 0) {
this._files.splice(0, lastIndex);
setTimeout(function () {
_this._retries = -1;
_this.downloadFiles(_this._files, _this._fileHandler);
}, this._retryTimeout);
}
else {
this.emit('error');
}
};
return FileReplicator;
}(events.EventEmitter));
}(EventEmitter));
var CONFIG_ITEM_KEY = "itemKey";
var CONFIG_ITEM_VALUE = "itemValue";
var CONFIG_ITEM_SOURCE_ATTRIBUTE = "itemSourceAttribute";
var CONFIG_ITEM_TARGET_ATTRIBUTE = "itemTargetAttribute";
var CONFIG_ITEM_VALIDATOR = "itemValidator";
var CONFIG_RETRY_TIMEOUT = "retryTimeout";
var CONFIG_FILE_HANDLER = "fileHandler";
var CONFIG_TARGET_DIRECTORY = "targetDirectory";
var Config = (function () {
function Config() {
this.config = {};
......@@ -263,6 +869,7 @@ var Config = (function () {
};
Config.prototype.setConfig = function (key, value) {
this.config[key] = value;
return this;
};
return Config;
}());
......@@ -300,7 +907,7 @@ var ServiceLocator = (function () {
return new ElectronFileHandler(window['require']('electron').ipcRenderer);
}
if (environment === ENV_CORDOVA) {
return new CordovaDownloader();
return new CordovaFileHandler();
}
return null;
};
......@@ -308,6 +915,7 @@ var ServiceLocator = (function () {
if (!ServiceLocator.fileReplicator) {
ServiceLocator.fileReplicator = new FileReplicator();
ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler();
}
if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) {
ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT);
}
......@@ -323,6 +931,8 @@ var ServiceLocator = (function () {
if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) {
ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE);
}
if (ServiceLocator.getConfig().hasConfig(CONFIG_TARGET_DIRECTORY)) {
ServiceLocator.fileReplicator.targetDirectory = ServiceLocator.getConfig().getConfig(CONFIG_TARGET_DIRECTORY);
}
return ServiceLocator.fileReplicator;
};
......@@ -330,61 +940,21 @@ var ServiceLocator = (function () {
return ServiceLocator;
}());
function loadBsyncPlugin(PouchDB) {
var pouchReplicate = PouchDB.replicate;
PouchDB.plugin(function (PouchDB) {
PouchDB.replicate = function () {
var eventEmitter = new events.EventEmitter();
var emitter = pouchReplicate.apply(this, arguments);
var replicator = ServiceLocator.getFileReplicator();
var db = arguments[1];
replicator.once('final', function (event) {
eventEmitter.emit('complete');
eventEmitter.removeAllListeners();
});
replicator.on('error', function (event) {
eventEmitter.emit('file-replicator-error', event);
});
replicator.on('complete', function (event) {
eventEmitter.emit('file-replicator-complete', event);
});
replicator.on('progress', function (event) {
eventEmitter.emit('file-replicator-progress', event);
});
emitter.once('change', function (info) {
eventEmitter.emit('change', info);
});
emitter.once('complete', function (info) {
db.query('index_type/type', {
include_docs: true,
key: replicator.itemValue
}).then(function (res) {
var docs = { docs: [] };
for (var _i = 0, _a = res.rows; _i < _a.length; _i++) {
var r = _a[_i];
docs.docs.push(r.doc);
}
replicator.pushChanges(docs);
replicator.start();
}).catch(function (error) {
eventEmitter.emit('error', error);
});
});
emitter.once('error', function (error) {
eventEmitter.emit('error', error);
});
return eventEmitter;
};
});
}
if (typeof window !== 'undefined' && window['PouchDB']) {
loadBsyncPlugin(window['PouchDB']);
}
exports.loadBsyncPlugin = loadBsyncPlugin;
exports.ENV_ELECTRON = ENV_ELECTRON;
exports.ENV_CORDOVA = ENV_CORDOVA;
exports.ENV_UNKNOWN = ENV_UNKNOWN;
exports.ServiceLocator = ServiceLocator;
exports.CONFIG_ITEM_KEY = CONFIG_ITEM_KEY;
exports.CONFIG_ITEM_VALUE = CONFIG_ITEM_VALUE;
exports.CONFIG_ITEM_SOURCE_ATTRIBUTE = CONFIG_ITEM_SOURCE_ATTRIBUTE;
exports.CONFIG_ITEM_TARGET_ATTRIBUTE = CONFIG_ITEM_TARGET_ATTRIBUTE;
exports.CONFIG_ITEM_VALIDATOR = CONFIG_ITEM_VALIDATOR;
exports.CONFIG_RETRY_TIMEOUT = CONFIG_RETRY_TIMEOUT;
exports.CONFIG_FILE_HANDLER = CONFIG_FILE_HANDLER;
exports.CONFIG_TARGET_DIRECTORY = CONFIG_TARGET_DIRECTORY;
exports.Config = Config;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=browser-build.js.map
......
{"version":3,"file":null,"sources":["../src/file-handler/electron-file-handler.ts","../src/file-handler/cordova-file-handler.ts","../src/util.ts","../src/file-replicator.ts","../src/config.ts","../src/service-locator.ts","../src/browser-main.ts"],"sourcesContent":["import { Observable, Subscriber } from 'rxjs';\nimport { FileHandler } from '../api/file-handler';\n\nexport class ElectronFileHandler implements FileHandler {\n\n constructor (private ipcRenderer:any) {\n }\n\n download(source:string, target:string) : Observable<number> {\n return Observable.create((subscriber:Subscriber<number>) => {\n\n this.ipcRenderer.once('bsync-download-complete', () => {\n this.ipcRenderer.removeAllListeners('bsync-download-progress');\n this.ipcRenderer.removeAllListeners('bsync-download-error');\n subscriber.complete();\n });\n\n this.ipcRenderer.on('bsync-download-progress', (progress:number) => {\n subscriber.next(progress);\n });\n\n this.ipcRenderer.once('bsync-download-error', (error:any) => {\n this.ipcRenderer.removeAllListeners('bsync-download-progress');\n this.ipcRenderer.removeAllListeners('bsync-download-complete');\n subscriber.error(error);\n });\n\n this.ipcRenderer.send('bsync-download', {\n source : source ,\n target : target\n });\n });\n }\n\n}","import { FileHandler } from '../api/file-handler';\n\ndeclare var Rx;\n\nexport class CordovaDownloader implements FileHandler {\n\n download(source:string, target:string) : Rx.Observable<number> {\n return Rx.Observable.create((subscriber:Rx.Subscriber<number>) => {\n\n if (!window['FileTransfer']) {\n subscriber.error(\"Cordova FileTransfer object undefined\");\n }\n\n let fileTransfer = new window['FileTransfer']();\n\n fileTransfer.onprogress = (progress:ProgressEvent) => {\n subscriber.next(progress.loaded / progress.total);\n };\n\n fileTransfer.download(\n source ,\n target ,\n (entry:any) => {\n subscriber.complete();\n } ,\n (error:any) => {\n subscriber.error(error);\n },\n true\n );\n\n }); \n }\n\n}","export class Util {\n\n static getNameHash(path:string) {\n for(var r=0,i=0;i<path.length;i++) {\n r=(r<<5)-r+path.charCodeAt(i),r&=r;\n }\n return \"bsync_\" + Math.abs(r);\n }\n\n}","import {FileHandler} from './api/file-handler';\nimport {File} from './api/file';\nimport {Util} from './util';\nimport {EventEmitter} from 'events';\n\nexport class FileReplicator extends EventEmitter {\n\n constructor() {\n super();\n }\n\n protected _files:Array<File> = [];\n\n protected _itemValidator: (item:any) => boolean = null; \n protected _fileHandler:FileHandler = null; \n protected _retryTimeout:number = 0;\n \n protected _itemKey = \"type\";\n protected _itemValue = \"asset\";\n protected _itemSourceAttribute = \"source\";\n protected _itemTargetAttribute = \"target\";\n\n get files(): Array<File> {\n return this._files;\n }\n\n set fileHandler (handler:FileHandler) {\n this._fileHandler = handler;\n }\n\n set retryTimeout (timeout:number) {\n this._retryTimeout = timeout;\n }\n\n set itemValidator(validator:(item:any) => boolean) {\n this._itemValidator = validator;\n }\n\n set itemKey(key:string) {\n this._itemKey = key;\n }\n\n set itemValue(value:string) {\n this._itemValue = value;\n }\n\n set itemSourceAttribute(sourceAttribute:string) {\n this._itemSourceAttribute = sourceAttribute;\n }\n\n set itemTargetAttribute(targetAttribute:string) {\n this._itemTargetAttribute = targetAttribute;\n }\n\n get itemKey() {\n return this._itemKey;\n }\n\n get itemValue() {\n return this._itemValue;\n }\n\n get itemSourceAttribute() {\n return this._itemSourceAttribute;\n }\n\n get itemTargetAttribute() {\n return this._itemTargetAttribute;\n }\n\n init(files: Array<File> = []) {\n this._files = files;\n }\n\n /**\n * change from pouchdb replicate\n */\n pushChanges(change:any) {\n let items:Array<any> = [];\n\n if (change && change.docs && change.docs.length > 0) {\n for (let item of change.docs) {\n if (item[this._itemKey] && item[this._itemKey] === this._itemValue) {\n items.push(item);\n }\n }\n }\n \n let files = this.prepareFiles(items);\n\n for (let file of files) {\n this._files.push(file);\n }\n }\n\n downloadFiles(files:Array<File>, fileHandler:FileHandler, index:number = 0) { \n if (index >= files.length) {\n return;\n }\n\n this.emit('start', { progress: 0, index : index, length : files.length });\n\n fileHandler\n .download(files[index].source, files[index].target)\n .subscribe(\n progress => {\n this.emit('progress', { progress : progress, index : index, length : files.length })\n } ,\n error => {\n this.emit('error', { progress : 0, index : index, length : files.length, error: error });\n } ,\n () => {\n this.emit('complete', { progress : 100 , index : index, length : files.length });\n this.downloadFiles(files, fileHandler, index+1);\n }\n );\n }\n\n prepareFiles(items: Array<any>) : Array<File> {\n let output = [];\n\n for (let item of items) {\n if (item[this._itemSourceAttribute] && (!this._itemValidator || this._itemValidator(item))) {\n let file = { source : item[this._itemSourceAttribute] , target : '' };\n\n if (item[this._itemTargetAttribute]) {\n file.target = item[this._itemTargetAttribute];\n } else {\n file.target = Util.getNameHash(file.source);\n }\n\n output.push(file);\n }\n }\n\n return output;\n }\n\n start() {\n this.on('complete', (event:any) => {\n if ((event.index + 1) >= event.length) {\n this.replicationFinalized(event.index);\n }\n });\n\n this.on('error', (event:any) => {\n this.replicationFinalized(event.index);\n }); \n\n this.downloadFiles(this._files, this._fileHandler);\n }\n\n replicationFinalized(lastIndex:number) { \n if (lastIndex+1 >= this._files.length) { // all finished\n this._files = [];\n this.emit('final');\n } else if (this._retryTimeout > 0) { // restart after last success \n this._files.splice(0,lastIndex);\n setTimeout(() => { \n this.downloadFiles(this._files, this._fileHandler);\n }, this._retryTimeout);\n } \n }\n\n}","export const CONFIG_ITEM_KEY = \"itemKey\";\nexport const CONFIG_ITEM_VALUE = \"itemValue\";\nexport const CONFIG_ITEM_SOURCE_ATTRIBUTE = \"itemSourceAttribute\";\nexport const CONFIG_ITEM_TARGET_ATTRIBUTE = \"itemTargetAttribute\";\nexport const CONFIG_ITEM_VALIDATOR = \"itemValidator\";\nexport const CONFIG_RETRY_TIMEOUT = \"retryTimeout\";\nexport const CONFIG_FILE_HANDLER = \"fileHandler\";\n\nexport class Config {\n\n protected config:any = {};\n\n hasConfig(key:string) {\n if (this.config[key]) {\n return true;\n }\n return false;\n }\n\n getConfig(key:string) {\n return this.config[key];\n }\n\n setConfig(key:string, value:any) {\n this.config[key] = value;\n }\n\n}","import {FileHandler} from './api/file-handler';\nimport {ElectronFileHandler} from './file-handler/electron-file-handler';\nimport {CordovaDownloader} from './file-handler/cordova-file-handler';\nimport {FileReplicator} from './file-replicator';\nimport {\n Config,\n CONFIG_RETRY_TIMEOUT,\n CONFIG_ITEM_KEY,\n CONFIG_ITEM_VALUE,\n CONFIG_ITEM_TARGET_ATTRIBUTE,\n CONFIG_ITEM_SOURCE_ATTRIBUTE\n} from './config';\n\nexport const ENV_ELECTRON = \"electron\";\nexport const ENV_CORDOVA = \"cordova\";\nexport const ENV_UNKNOWN = \"unknown\";\n\nexport class ServiceLocator {\n\n protected static fileHandlers:any = {};\n protected static fileReplicator: FileReplicator;\n protected static config: Config;\n\n static addFileHandler(environment:string, fileHandler:FileHandler) {\n ServiceLocator.fileHandlers[environment] = fileHandler;\n }\n\n static getConfig() : Config {\n if (!ServiceLocator.config) {\n ServiceLocator.config = new Config();\n }\n\n return ServiceLocator.config;\n }\n\n static getEnvironment() {\n if (typeof window['require'] === 'function' && window['require']('electron')) {\n return ENV_ELECTRON;\n }\n if (typeof window['FileTransfer'] === 'function') {\n return ENV_CORDOVA;\n }\n\n return ENV_UNKNOWN;\n }\n\n static getFileHandler() : FileHandler {\n let environment = ServiceLocator.getEnvironment();\n\n if (ServiceLocator.fileHandlers[environment]) {\n return ServiceLocator.fileHandlers[environment];\n }\n\n if (environment === ENV_ELECTRON) {\n return new ElectronFileHandler(window['require']('electron').ipcRenderer);\n }\n\n if (environment === ENV_CORDOVA) {\n return new CordovaDownloader();\n }\n \n return null;\n }\n\n static getFileReplicator() : FileReplicator {\n if (!ServiceLocator.fileReplicator) {\n\n ServiceLocator.fileReplicator = new FileReplicator();\n\n ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler();\n\n if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) {\n ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_KEY)) {\n ServiceLocator.fileReplicator.itemKey = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_KEY);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_VALUE)) {\n ServiceLocator.fileReplicator.itemValue = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_VALUE);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE)) {\n ServiceLocator.fileReplicator.itemSourceAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) {\n ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE);\n }\n } \n\n return ServiceLocator.fileReplicator;\n }\n\n}","import { EventEmitter } from 'events';\nimport { ServiceLocator } from './service-locator';\n\nexport * from './service-locator';\n\nexport function loadBsyncPlugin (PouchDB) {\n let pouchReplicate = PouchDB.replicate; \n\n PouchDB.plugin((PouchDB) => {\n PouchDB.replicate = function() {\n let eventEmitter = new EventEmitter();\n let emitter = pouchReplicate.apply(this, arguments);\n let replicator = ServiceLocator.getFileReplicator();\n let db = arguments[1]; \n \n replicator.once('final', event => { \n eventEmitter.emit('complete');\n eventEmitter.removeAllListeners();\n });\n\n replicator.on('error', event => {\n eventEmitter.emit('file-replicator-error', event);\n });\n\n replicator.on('complete', event => {\n eventEmitter.emit('file-replicator-complete', event);\n });\n\n replicator.on('progress', event => {\n eventEmitter.emit('file-replicator-progress', event);\n });\n \n emitter.once('change', info => { \n eventEmitter.emit('change', info);\n });\n\n emitter.once('complete', info => { \n db.query('index_type/type',{\n include_docs : true,\n key : replicator.itemValue\n }).then((res) => { \n let docs = { docs : [] }; \n for (let r of res.rows) {\n docs.docs.push(r.doc);\n }\n\n replicator.pushChanges(docs);\n replicator.start();\n }).catch(error => {\n eventEmitter.emit('error', error);\n });\n });\n\n emitter.once('error', (error) => {\n eventEmitter.emit('error', error);\n });\n\n return eventEmitter;\n };\n });\n};\n\nif (typeof window !== 'undefined' && window['PouchDB']) {\n loadBsyncPlugin(window['PouchDB']);\n}\n"],"names":["Observable","EventEmitter"],"mappings":"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"}
\ No newline at end of file
{"version":3,"file":null,"sources":["../node_modules/rollup-plugin-node-builtins/src/es6/events.js","../src/file-handler/electron-file-handler.ts","../src/util.ts","../src/file-handler/cordova-file-handler.ts","../src/file-replicator.ts","../src/config.ts","../src/service-locator.ts"],"sourcesContent":["'use strict';\n\nvar domain;\n\n// This constructor is used to store event handlers. Instantiating this is\n// faster than explicitly calling `Object.create(null)` to get a \"clean\" empty\n// object (tested with v8 v4.9).\nfunction EventHandlers() {}\nEventHandlers.prototype = Object.create(null);\n\nfunction EventEmitter() {\n EventEmitter.init.call(this);\n}\nexport default EventEmitter;\nexport {EventEmitter};\n\nEventEmitter.usingDomains = false;\n\nEventEmitter.prototype.domain = undefined;\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nEventEmitter.defaultMaxListeners = 10;\n\nEventEmitter.init = function() {\n this.domain = null;\n if (EventEmitter.usingDomains) {\n // if there is an active domain, then attach to it.\n if (domain.active && !(this instanceof domain.Domain)) {\n this.domain = domain.active;\n }\n }\n\n if (!this._events || this._events === Object.getPrototypeOf(this)._events) {\n this._events = new EventHandlers();\n this._eventsCount = 0;\n }\n\n this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n if (typeof n !== 'number' || n < 0 || isNaN(n))\n throw new TypeError('\"n\" argument must be a positive number');\n this._maxListeners = n;\n return this;\n};\n\nfunction $getMaxListeners(that) {\n if (that._maxListeners === undefined)\n return EventEmitter.defaultMaxListeners;\n return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n return $getMaxListeners(this);\n};\n\n// These standalone emit* functions are used to optimize calling of event\n// handlers for fast cases because emit() itself often has a variable number of\n// arguments and can be deoptimized because of that. These functions always have\n// the same number of arguments and thus do not get deoptimized, so the code\n// inside them can execute faster.\nfunction emitNone(handler, isFn, self) {\n if (isFn)\n handler.call(self);\n else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n listeners[i].call(self);\n }\n}\nfunction emitOne(handler, isFn, self, arg1) {\n if (isFn)\n handler.call(self, arg1);\n else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n listeners[i].call(self, arg1);\n }\n}\nfunction emitTwo(handler, isFn, self, arg1, arg2) {\n if (isFn)\n handler.call(self, arg1, arg2);\n else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n listeners[i].call(self, arg1, arg2);\n }\n}\nfunction emitThree(handler, isFn, self, arg1, arg2, arg3) {\n if (isFn)\n handler.call(self, arg1, arg2, arg3);\n else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n listeners[i].call(self, arg1, arg2, arg3);\n }\n}\n\nfunction emitMany(handler, isFn, self, args) {\n if (isFn)\n handler.apply(self, args);\n else {\n var len = handler.length;\n var listeners = arrayClone(handler, len);\n for (var i = 0; i < len; ++i)\n listeners[i].apply(self, args);\n }\n}\n\nEventEmitter.prototype.emit = function emit(type) {\n var er, handler, len, args, i, events, domain;\n var needDomainExit = false;\n var doError = (type === 'error');\n\n events = this._events;\n if (events)\n doError = (doError && events.error == null);\n else if (!doError)\n return false;\n\n domain = this.domain;\n\n // If there is no 'error' event listener then throw.\n if (doError) {\n er = arguments[1];\n if (domain) {\n if (!er)\n er = new Error('Uncaught, unspecified \"error\" event');\n er.domainEmitter = this;\n er.domain = domain;\n er.domainThrown = false;\n domain.emit('error', er);\n } else if (er instanceof Error) {\n throw er; // Unhandled 'error' event\n } else {\n // At least give some kind of context to the user\n var err = new Error('Uncaught, unspecified \"error\" event. (' + er + ')');\n err.context = er;\n throw err;\n }\n return false;\n }\n\n handler = events[type];\n\n if (!handler)\n return false;\n\n var isFn = typeof handler === 'function';\n len = arguments.length;\n switch (len) {\n // fast cases\n case 1:\n emitNone(handler, isFn, this);\n break;\n case 2:\n emitOne(handler, isFn, this, arguments[1]);\n break;\n case 3:\n emitTwo(handler, isFn, this, arguments[1], arguments[2]);\n break;\n case 4:\n emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);\n break;\n // slower\n default:\n args = new Array(len - 1);\n for (i = 1; i < len; i++)\n args[i - 1] = arguments[i];\n emitMany(handler, isFn, this, args);\n }\n\n if (needDomainExit)\n domain.exit();\n\n return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n var m;\n var events;\n var existing;\n\n if (typeof listener !== 'function')\n throw new TypeError('\"listener\" argument must be a function');\n\n events = target._events;\n if (!events) {\n events = target._events = new EventHandlers();\n target._eventsCount = 0;\n } else {\n // To avoid recursion in the case that type === \"newListener\"! Before\n // adding it to the listeners, first emit \"newListener\".\n if (events.newListener) {\n target.emit('newListener', type,\n listener.listener ? listener.listener : listener);\n\n // Re-assign `events` because a newListener handler could have caused the\n // this._events to be assigned to a new object\n events = target._events;\n }\n existing = events[type];\n }\n\n if (!existing) {\n // Optimize the case of one listener. Don't need the extra array object.\n existing = events[type] = listener;\n ++target._eventsCount;\n } else {\n if (typeof existing === 'function') {\n // Adding the second element, need to change to array.\n existing = events[type] = prepend ? [listener, existing] :\n [existing, listener];\n } else {\n // If we've already got an array, just append.\n if (prepend) {\n existing.unshift(listener);\n } else {\n existing.push(listener);\n }\n }\n\n // Check for listener leak\n if (!existing.warned) {\n m = $getMaxListeners(target);\n if (m && m > 0 && existing.length > m) {\n existing.warned = true;\n var w = new Error('Possible EventEmitter memory leak detected. ' +\n existing.length + ' ' + type + ' listeners added. ' +\n 'Use emitter.setMaxListeners() to increase limit');\n w.name = 'MaxListenersExceededWarning';\n w.emitter = target;\n w.type = type;\n w.count = existing.length;\n emitWarning(w);\n }\n }\n }\n\n return target;\n}\nfunction emitWarning(e) {\n typeof console.warn === 'function' ? console.warn(e) : console.log(e);\n}\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n function prependListener(type, listener) {\n return _addListener(this, type, listener, true);\n };\n\nfunction _onceWrap(target, type, listener) {\n var fired = false;\n function g() {\n target.removeListener(type, g);\n if (!fired) {\n fired = true;\n listener.apply(target, arguments);\n }\n }\n g.listener = listener;\n return g;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n if (typeof listener !== 'function')\n throw new TypeError('\"listener\" argument must be a function');\n this.on(type, _onceWrap(this, type, listener));\n return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n function prependOnceListener(type, listener) {\n if (typeof listener !== 'function')\n throw new TypeError('\"listener\" argument must be a function');\n this.prependListener(type, _onceWrap(this, type, listener));\n return this;\n };\n\n// emits a 'removeListener' event iff the listener was removed\nEventEmitter.prototype.removeListener =\n function removeListener(type, listener) {\n var list, events, position, i, originalListener;\n\n if (typeof listener !== 'function')\n throw new TypeError('\"listener\" argument must be a function');\n\n events = this._events;\n if (!events)\n return this;\n\n list = events[type];\n if (!list)\n return this;\n\n if (list === listener || (list.listener && list.listener === listener)) {\n if (--this._eventsCount === 0)\n this._events = new EventHandlers();\n else {\n delete events[type];\n if (events.removeListener)\n this.emit('removeListener', type, list.listener || listener);\n }\n } else if (typeof list !== 'function') {\n position = -1;\n\n for (i = list.length; i-- > 0;) {\n if (list[i] === listener ||\n (list[i].listener && list[i].listener === listener)) {\n originalListener = list[i].listener;\n position = i;\n break;\n }\n }\n\n if (position < 0)\n return this;\n\n if (list.length === 1) {\n list[0] = undefined;\n if (--this._eventsCount === 0) {\n this._events = new EventHandlers();\n return this;\n } else {\n delete events[type];\n }\n } else {\n spliceOne(list, position);\n }\n\n if (events.removeListener)\n this.emit('removeListener', type, originalListener || listener);\n }\n\n return this;\n };\n\nEventEmitter.prototype.removeAllListeners =\n function removeAllListeners(type) {\n var listeners, events;\n\n events = this._events;\n if (!events)\n return this;\n\n // not listening for removeListener, no need to emit\n if (!events.removeListener) {\n if (arguments.length === 0) {\n this._events = new EventHandlers();\n this._eventsCount = 0;\n } else if (events[type]) {\n if (--this._eventsCount === 0)\n this._events = new EventHandlers();\n else\n delete events[type];\n }\n return this;\n }\n\n // emit removeListener for all listeners on all events\n if (arguments.length === 0) {\n var keys = Object.keys(events);\n for (var i = 0, key; i < keys.length; ++i) {\n key = keys[i];\n if (key === 'removeListener') continue;\n this.removeAllListeners(key);\n }\n this.removeAllListeners('removeListener');\n this._events = new EventHandlers();\n this._eventsCount = 0;\n return this;\n }\n\n listeners = events[type];\n\n if (typeof listeners === 'function') {\n this.removeListener(type, listeners);\n } else if (listeners) {\n // LIFO order\n do {\n this.removeListener(type, listeners[listeners.length - 1]);\n } while (listeners[0]);\n }\n\n return this;\n };\n\nEventEmitter.prototype.listeners = function listeners(type) {\n var evlistener;\n var ret;\n var events = this._events;\n\n if (!events)\n ret = [];\n else {\n evlistener = events[type];\n if (!evlistener)\n ret = [];\n else if (typeof evlistener === 'function')\n ret = [evlistener.listener || evlistener];\n else\n ret = unwrapListeners(evlistener);\n }\n\n return ret;\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n if (typeof emitter.listenerCount === 'function') {\n return emitter.listenerCount(type);\n } else {\n return listenerCount.call(emitter, type);\n }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n var events = this._events;\n\n if (events) {\n var evlistener = events[type];\n\n if (typeof evlistener === 'function') {\n return 1;\n } else if (evlistener) {\n return evlistener.length;\n }\n }\n\n return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];\n};\n\n// About 1.5x faster than the two-arg version of Array#splice().\nfunction spliceOne(list, index) {\n for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)\n list[i] = list[k];\n list.pop();\n}\n\nfunction arrayClone(arr, i) {\n var copy = new Array(i);\n while (i--)\n copy[i] = arr[i];\n return copy;\n}\n\nfunction unwrapListeners(arr) {\n var ret = new Array(arr.length);\n for (var i = 0; i < ret.length; ++i) {\n ret[i] = arr[i].listener || arr[i];\n }\n return ret;\n}\n","import { EventEmitter } from 'events';\nimport { FileHandler } from '../api/file-handler';\nimport { File } from '../api/file';\n\nexport class ElectronFileHandler extends EventEmitter implements FileHandler {\n\n constructor (private ipcRenderer:any) {\n super();\n }\n\n download(source:string, target:string) {\n this.ipcRenderer.once('bsync-download-complete', () => {\n this.ipcRenderer.removeAllListeners('bsync-download-progress');\n this.ipcRenderer.removeAllListeners('bsync-download-error');\n this.emit('complete');\n });\n\n this.ipcRenderer.on('bsync-download-progress', (progress:number) => {\n this.emit('progress', progress);\n });\n\n this.ipcRenderer.once('bsync-download-error', (error:any) => {\n this.ipcRenderer.removeAllListeners('bsync-download-progress');\n this.ipcRenderer.removeAllListeners('bsync-download-complete');\n this.emit('error', error);\n });\n\n this.ipcRenderer.send('bsync-download', {\n source : source ,\n target : target\n });\n\n return this; \n }\n\n cleanup(files:Array<File>) : Promise<void> {\n return new Promise<void>((resolve, reject) => {\n\n this.ipcRenderer.once('bsync-cleanup-complete', () => {\n this.emit('cleanup-complete');\n resolve();\n });\n\n this.ipcRenderer.send('bsync-cleanup', files);\n\n });\n }\n\n}","import { File } from './api/file';\n\nexport class Util {\n\n static getNameHash(path:string) {\n for(var r=0,i=0;i<path.length;i++) {\n r=(r<<5)-r+path.charCodeAt(i),r&=r;\n }\n return \"bsync_\" + Math.abs(r);\n }\n\n /**\n * index >= 0, localFile is in files\n * index < 0, localFile is not in files\n */\n static getFileIndex(files:Array<File>, localFile:string) : number {\n for (let i = 0; i < files.length; i++) {\n if (localFile == files[i].target) {\n return i;\n }\n }\n return -1;\n }\n\n static getFilesForCleanup(files:Array<File>, localFiles:Array<string>) : Array<string> {\n let filesForCleanup = [];\n\n for (let localFile of localFiles) {\n let index = -1;\n\n index = Util.getFileIndex(files, localFile);\n \n if (index < 0) {\n filesForCleanup.push(localFile);\n } else {\n // splice for performance improvement only\n files.splice(index,1);\n }\n }\n\n return filesForCleanup;\n }\n\n}","import { Util } from './../util';\nimport { EventEmitter } from 'events';\nimport { FileHandler } from '../api/file-handler';\nimport { File } from '../api/file';\n\nexport class CordovaFileHandler extends EventEmitter implements FileHandler {\n\n triggerFileTransfer(source:string, target:string) {\n let fileTransfer = new window['FileTransfer']();\n\n fileTransfer.onprogress = (progress:ProgressEvent) => {\n this.emit('progress', progress.loaded / progress.total);\n };\n\n fileTransfer.download(\n source ,\n target ,\n (entry:any) => {\n this.emit('complete', entry);\n } ,\n (error:any) => {\n this.emit('error', error);\n },\n true\n );\n }\n\n download(source:string, target:string) {\n if (!window['FileTransfer']) {\n this.emit('error','Cordova FileTransfer object undefined');\n }\n\n window['resolveLocalFileSystemURL'](target, (entry:any) => {\n entry.getMetadata((metadata) => {\n if (metadata.size > 0) {\n this.emit('complete', entry);\n } else {\n // file empty trigger transfer\n this.triggerFileTransfer(source,target);\n }\n }, () => {\n // cannot read metadata trigger transfer\n this.triggerFileTransfer(source,target);\n });\n }, () => {\n // file not found, so download it\n this.triggerFileTransfer(source,target);\n });\n\n return this; \n }\n\n cleanup(files:Array<File>, basePath:string) : Promise<void> {\n let filesForCleanup = [];\n\n return new Promise<void>((resolve, reject) => {\n\n if (window['resolveLocalFileSystemURL']) {\n window['resolveLocalFileSystemURL'](basePath, (entry) => {\n let reader = entry.createReader();\n reader.readEntries((entries) => {\n\n for (let e of entries) {\n if (e && e.isFile) {\n if (Util.getFileIndex(files, e.name) < 0) {\n filesForCleanup.push(e);\n }\n }\n }\n \n let index = 0;\n let error = false;\n\n let cleanupError = (error) => {\n this.emit('cleanup-error', error);\n reject();\n error = true;\n };\n\n let cleanupNext = () => {\n if (index < filesForCleanup.length && !error) {\n filesForCleanup[index].remove(cleanupNext, cleanupError);\n index += 1;\n } else if (!error) { \n this.emit('cleanup-complete', filesForCleanup);\n resolve();\n }\n };\n \n cleanupNext();\n\n }, (error) => { this.emit('cleanup-error', error); reject(); });\n });\n }\n\n });\n }\n\n}","import { FileHandler } from './api/file-handler';\nimport { File } from './api/file';\nimport { Util } from './util';\nimport { EventEmitter } from 'events';\n\nexport class FileReplicator extends EventEmitter {\n\n constructor() {\n super();\n }\n\n protected _files: Array<File> = [];\n\n protected _itemValidator: (item: any) => boolean = null;\n protected _fileHandler: FileHandler = null;\n protected _retryTimeout: number = 100;\n protected _retries: number = 10;\n\n protected _itemKey = \"type\";\n protected _itemValue = \"asset\";\n protected _itemSourceAttribute = \"source\";\n protected _itemTargetAttribute = \"target\";\n protected _targetDirectory = \"\";\n\n get files(): Array<File> {\n return this._files;\n }\n\n set fileHandler(handler: FileHandler) {\n this._fileHandler = handler;\n }\n\n get fileHandler() : FileHandler {\n return this._fileHandler;\n }\n\n set retryTimeout(timeout: number) {\n this._retryTimeout = timeout;\n }\n\n set itemValidator(validator: (item: any) => boolean) {\n this._itemValidator = validator;\n }\n\n set itemKey(key: string) {\n this._itemKey = key;\n }\n\n set itemValue(value: string) {\n this._itemValue = value;\n }\n\n set itemSourceAttribute(sourceAttribute: string) {\n this._itemSourceAttribute = sourceAttribute;\n }\n\n set itemTargetAttribute(targetAttribute: string) {\n this._itemTargetAttribute = targetAttribute;\n }\n\n get itemKey() {\n return this._itemKey;\n }\n\n get itemValue() {\n return this._itemValue;\n }\n\n get itemSourceAttribute() {\n return this._itemSourceAttribute;\n }\n\n get itemTargetAttribute() {\n return this._itemTargetAttribute;\n }\n\n set targetDirectory(targetDirectory: string) {\n this._targetDirectory = targetDirectory;\n }\n\n get targetDirectory() {\n return this._targetDirectory;\n }\n\n clear(files: Array<File> = []) {\n this._files = files;\n }\n\n /**\n * change from pouchdb replicate\n */\n pushChanges(docs: Array<any>) {\n let items: Array<any> = [];\n\n if (docs && docs.length > 0) {\n for (let item of docs) {\n if (item[this._itemKey] && item[this._itemKey] === this._itemValue) {\n items.push(item);\n }\n }\n }\n\n let files = this.prepareFiles(items);\n\n for (let file of files) {\n this._files.push(file);\n }\n }\n\n downloadFiles(files: Array<File>, fileHandler: FileHandler, index: number = 0) {\n if (index >= files.length) {\n return;\n }\n\n this.emit('start', { progress: 0, index: index, length: files.length });\n \n fileHandler\n .on('progress', (progress) => {\n this.emit('file-progress', { progress: progress, index: index, length: files.length })\n })\n .once('error', error => {\n this.emit('file-error', { progress: 0, index: index, length: files.length, error: error });\n fileHandler.removeAllListeners();\n })\n .once('complete', () => {\n this.emit('file-complete', { progress: 100, index: index, length: files.length });\n fileHandler.removeAllListeners();\n this.downloadFiles(files, fileHandler, index + 1);\n })\n .download(files[index].source, this.targetDirectory + files[index].target); \n }\n\n prepareFiles(items: Array<any>): Array<File> {\n let output = [];\n\n for (let item of items) {\n if (item[this._itemSourceAttribute] && (!this._itemValidator || this._itemValidator(item))) {\n let file = { source: item[this._itemSourceAttribute], target: '' };\n\n if (item[this._itemTargetAttribute]) {\n file.target = item[this._itemTargetAttribute];\n } else {\n file.target = Util.getNameHash(file.source);\n }\n\n output.push(file);\n }\n }\n\n return output;\n }\n\n start(retries:number = 10) {\n this._retries = retries;\n\n this.on('file-complete', (event: any) => {\n if ((event.index + 1) >= event.length) {\n this.replicationFinalized(event.index);\n }\n });\n\n this.on('file-error', (event: any) => {\n this.replicationFinalized(event.index);\n });\n\n if (this._fileHandler && this._files.length > 0) {\n this.downloadFiles(this._files, this._fileHandler);\n } else {\n this.emit('complete');\n } \n }\n\n cleanup() {\n this.fileHandler\n .cleanup(this._files, this._targetDirectory)\n .then(() => {\n this.emit('cleanup-complete');\n }).catch(() => {\n this.emit('cleanup-error');\n });\n }\n\n replicationFinalized(lastIndex: number) {\n if (lastIndex + 1 >= this._files.length) { // all finished\n this.emit('complete');\n } else if (this._retries > 0) { // restart after last success \n this._files.splice(0, lastIndex);\n setTimeout(() => {\n this._retries =- 1;\n this.downloadFiles(this._files, this._fileHandler);\n }, this._retryTimeout);\n } else {\n this.emit('error');\n }\n }\n\n}","export const CONFIG_ITEM_KEY = \"itemKey\";\nexport const CONFIG_ITEM_VALUE = \"itemValue\";\nexport const CONFIG_ITEM_SOURCE_ATTRIBUTE = \"itemSourceAttribute\";\nexport const CONFIG_ITEM_TARGET_ATTRIBUTE = \"itemTargetAttribute\";\nexport const CONFIG_ITEM_VALIDATOR = \"itemValidator\";\nexport const CONFIG_RETRY_TIMEOUT = \"retryTimeout\";\nexport const CONFIG_FILE_HANDLER = \"fileHandler\";\nexport const CONFIG_TARGET_DIRECTORY = \"targetDirectory\";\n\nexport class Config {\n\n protected config:any = {};\n\n hasConfig(key:string) : boolean {\n if (this.config[key]) {\n return true;\n }\n return false;\n }\n\n getConfig(key:string) : any {\n return this.config[key];\n }\n\n setConfig(key:string, value:any) : Config {\n this.config[key] = value;\n return this;\n }\n\n}","import {FileHandler} from './api/file-handler';\nimport {ElectronFileHandler} from './file-handler/electron-file-handler';\nimport {CordovaFileHandler} from './file-handler/cordova-file-handler';\nimport {FileReplicator} from './file-replicator';\nimport {\n Config,\n CONFIG_RETRY_TIMEOUT,\n CONFIG_ITEM_KEY,\n CONFIG_ITEM_VALUE,\n CONFIG_ITEM_TARGET_ATTRIBUTE,\n CONFIG_ITEM_SOURCE_ATTRIBUTE,\n CONFIG_TARGET_DIRECTORY\n} from './config';\n\nexport const ENV_ELECTRON = \"electron\";\nexport const ENV_CORDOVA = \"cordova\";\nexport const ENV_UNKNOWN = \"unknown\";\n\nexport class ServiceLocator {\n\n protected static fileHandlers:any = {};\n protected static fileReplicator: FileReplicator;\n protected static config: Config;\n\n static addFileHandler(environment:string, fileHandler:FileHandler) {\n ServiceLocator.fileHandlers[environment] = fileHandler;\n }\n\n static getConfig() : Config {\n if (!ServiceLocator.config) {\n ServiceLocator.config = new Config();\n }\n\n return ServiceLocator.config;\n }\n\n static getEnvironment() {\n if (typeof window['require'] === 'function' && window['require']('electron')) {\n return ENV_ELECTRON;\n }\n if (typeof window['FileTransfer'] === 'function') {\n return ENV_CORDOVA;\n }\n\n return ENV_UNKNOWN;\n }\n\n static getFileHandler() : FileHandler {\n let environment = ServiceLocator.getEnvironment();\n\n if (ServiceLocator.fileHandlers[environment]) {\n return ServiceLocator.fileHandlers[environment];\n }\n\n if (environment === ENV_ELECTRON) {\n return new ElectronFileHandler(window['require']('electron').ipcRenderer);\n }\n\n if (environment === ENV_CORDOVA) {\n return new CordovaFileHandler();\n }\n \n return null;\n }\n\n static getFileReplicator() : FileReplicator {\n if (!ServiceLocator.fileReplicator) {\n ServiceLocator.fileReplicator = new FileReplicator();\n ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler();\n }\n\n if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) {\n ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_KEY)) {\n ServiceLocator.fileReplicator.itemKey = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_KEY);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_VALUE)) {\n ServiceLocator.fileReplicator.itemValue = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_VALUE);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE)) {\n ServiceLocator.fileReplicator.itemSourceAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) {\n ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE);\n }\n if (ServiceLocator.getConfig().hasConfig(CONFIG_TARGET_DIRECTORY)) {\n ServiceLocator.fileReplicator.targetDirectory = ServiceLocator.getConfig().getConfig(CONFIG_TARGET_DIRECTORY);\n }\n \n return ServiceLocator.fileReplicator;\n }\n\n}"],"names":[],"mappings":"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"}
\ No newline at end of file
......
'use strict';
var rxjs_Observable = require('rxjs/Observable');
var events = require('events');
var http = require('http');
var https = require('https');
var fs = require('fs');
var NodeFileHandler = (function () {
function __extends(d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var Util = (function () {
function Util() {
}
Util.getNameHash = function (path) {
for (var r = 0, i = 0; i < path.length; i++) {
r = (r << 5) - r + path.charCodeAt(i), r &= r;
}
return "bsync_" + Math.abs(r);
};
/**
* index >= 0, localFile is in files
* index < 0, localFile is not in files
*/
Util.getFileIndex = function (files, localFile) {
for (var i = 0; i < files.length; i++) {
if (localFile == files[i].target) {
return i;
}
}
return -1;
};
Util.getFilesForCleanup = function (files, localFiles) {
var filesForCleanup = [];
for (var _i = 0, localFiles_1 = localFiles; _i < localFiles_1.length; _i++) {
var localFile = localFiles_1[_i];
var index = -1;
index = Util.getFileIndex(files, localFile);
if (index < 0) {
filesForCleanup.push(localFile);
}
else {
// splice for performance improvement only
files.splice(index, 1);
}
}
return filesForCleanup;
};
return Util;
}());
var NodeFileHandler = (function (_super) {
__extends(NodeFileHandler, _super);
function NodeFileHandler() {
_super.apply(this, arguments);
}
NodeFileHandler.prototype.selectProtocol = function (url) {
if (url.search(/^http:\/\//) === 0) {
......@@ -20,18 +68,19 @@ var NodeFileHandler = (function () {
}
};
NodeFileHandler.prototype.download = function (source, target) {
var _this = this;
var handler = this.selectProtocol(source);
return rxjs_Observable.Observable.create(function (subscriber) {
if (!handler) {
subscriber.error("No handler for source: " + source);
return;
this.emit("error", "No handler for source: " + source);
return this;
}
// file already exists and is not empty
if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
subscriber.complete();
return;
this.emit("complete");
return this;
}
var file = fs.createWriteStream(target, { 'flags': 'a' });
else {
var file_1 = fs.createWriteStream(target, { 'flags': 'a' });
handler.get(source, function (response) {
var size = response.headers['content-length']; // in bytes
var prog = 0; // already downloaded
......@@ -39,33 +88,53 @@ var NodeFileHandler = (function () {
var nextProg = (1 / progCounts);
response.on('data', function (chunk) {
prog += chunk.length;
file.write(chunk, 'binary');
file_1.write(chunk, 'binary');
if ((prog / size) > nextProg) {
subscriber.next(prog / size);
_this.emit('progress', prog / size);
nextProg += (1 / progCounts);
}
});
response.on('end', function () {
file.end();
subscriber.complete();
response.once('end', function () {
file_1.end();
_this.emit('complete');
});
}).on('error', function (error) {
fs.unlink(target);
subscriber.error("Error while downloading: " + error);
_this.emit("error", "Error while downloading: " + error);
});
return this;
}
};
NodeFileHandler.prototype.cleanup = function (files, basePath) {
try {
var localFiles = fs.readdirSync(basePath);
Util.getFilesForCleanup(files, localFiles)
.forEach(function (file) {
fs.unlinkSync(basePath + "/" + file);
});
}
catch (e) {
}
return this;
};
return NodeFileHandler;
}());
}(events.EventEmitter));
var Bsync = (function () {
function Bsync() {
}
Bsync.configIpcMain = function (ipcMain, downloadDir) {
var nodeFileHander = new NodeFileHandler();
Bsync.configIpcMain = function (ipcMain, basePath) {
ipcMain.on('bsync-download', function (event, args) {
nodeFileHander.download(args.source, downloadDir + args.target)
.subscribe(function (progress) { event.sender.send('bsync-download-progress', progress); }, function (error) { event.sender.send('bsync-download-error', error); }, function () { event.sender.send('bsync-download-complete'); });
var nodeFileHander = new NodeFileHandler();
nodeFileHander.download(args.source, basePath + "/" + args.target)
.on('progress', function (progress) { event.sender.send('bsync-download-progress', progress); })
.once('error', function (error) { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-error', error); })
.once('complete', function () { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-complete'); });
});
ipcMain.on('bsync-cleanup', function (event, args) {
var nodeFileHandler = new NodeFileHandler();
nodeFileHandler.cleanup(args.files, basePath);
event.sender.send('bsync-cleanup-complete');
});
};
return Bsync;
......
{"version":3,"file":null,"sources":["../src/file-handler/node-file-handler.ts","../src/node-main.ts"],"sourcesContent":["import { Observable } from 'rxjs/Observable';\nimport { Subscriber } from 'rxjs/Subscriber';\nimport { FileHandler } from '../api/file-handler';\nimport * as http from 'http';\nimport * as https from 'https';\nimport * as fs from 'fs';\n\nexport class NodeFileHandler implements FileHandler {\n\n selectProtocol(url:string) : any {\n if (url.search(/^http:\\/\\//) === 0) {\n return http;\n } else if (url.search(/^https:\\/\\//) === 0) {\n return https;\n } else {\n return null;\n }\n }\n\n download(source:string, target:string) : Observable<number> {\n\n let handler = this.selectProtocol(source);\n\n return Observable.create((subscriber:Subscriber<number>) => {\n \n if (!handler) {\n subscriber.error(\"No handler for source: \" + source);\n return;\n }\n\n // file already exists and is not empty\n if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {\n subscriber.complete();\n return;\n }\n\n let file = fs.createWriteStream(target, {'flags': 'a'});\n\n handler.get(source, (response) => {\n let size = response.headers['content-length']; // in bytes\n let prog = 0; // already downloaded\n let progCounts = 100; // how many progress events should be triggerd (1-100 %)\n let nextProg = (1/progCounts);\n \n response.on('data', (chunk) => {\n prog += chunk.length;\n file.write(chunk, 'binary');\n\n if ((prog / size) > nextProg) {\n subscriber.next(prog / size);\n nextProg += (1 / progCounts);\n } \n });\n\n response.on('end', () => {\n file.end();\n subscriber.complete();\n });\n \n }).on('error', (error) => {\n fs.unlink(target);\n subscriber.error(\"Error while downloading: \" + error);\n });\n\n });\n\n }\n\n}","import { NodeFileHandler } from './file-handler/node-file-handler';\n\nexport default class Bsync {\n\n static configIpcMain(ipcMain: any, downloadDir:string) {\n let nodeFileHander = new NodeFileHandler();\n\n ipcMain.on('bsync-download', (event, args) => {\n nodeFileHander.download(args.source, downloadDir + args.target)\n .subscribe(\n (progress:number) => { event.sender.send('bsync-download-progress', progress); } ,\n (error:any) => { event.sender.send('bsync-download-error', error); } ,\n () => { event.sender.send('bsync-download-complete'); }\n );\n });\n }\n\n}"],"names":["Observable","fs.existsSync","fs.statSync","fs.createWriteStream","fs.unlink"],"mappings":"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"}
\ No newline at end of file
{"version":3,"file":null,"sources":["../src/util.ts","../src/file-handler/node-file-handler.ts","../src/node-main.ts"],"sourcesContent":["import { File } from './api/file';\n\nexport class Util {\n\n static getNameHash(path:string) {\n for(var r=0,i=0;i<path.length;i++) {\n r=(r<<5)-r+path.charCodeAt(i),r&=r;\n }\n return \"bsync_\" + Math.abs(r);\n }\n\n /**\n * index >= 0, localFile is in files\n * index < 0, localFile is not in files\n */\n static getFileIndex(files:Array<File>, localFile:string) : number {\n for (let i = 0; i < files.length; i++) {\n if (localFile == files[i].target) {\n return i;\n }\n }\n return -1;\n }\n\n static getFilesForCleanup(files:Array<File>, localFiles:Array<string>) : Array<string> {\n let filesForCleanup = [];\n\n for (let localFile of localFiles) {\n let index = -1;\n\n index = Util.getFileIndex(files, localFile);\n \n if (index < 0) {\n filesForCleanup.push(localFile);\n } else {\n // splice for performance improvement only\n files.splice(index,1);\n }\n }\n\n return filesForCleanup;\n }\n\n}","import { Util } from './../util';\nimport { EventEmitter } from 'events';\nimport { FileHandler } from '../api/file-handler';\nimport { File } from '../api/file';\nimport * as http from 'http';\nimport * as https from 'https';\nimport * as fs from 'fs';\n\nexport class NodeFileHandler extends EventEmitter implements FileHandler {\n\n selectProtocol(url:string) : any {\n if (url.search(/^http:\\/\\//) === 0) {\n return http;\n } else if (url.search(/^https:\\/\\//) === 0) {\n return https;\n } else {\n return null;\n }\n }\n\n download(source:string, target:string) {\n\n let handler = this.selectProtocol(source);\n\n if (!handler) {\n this.emit(\"error\",\"No handler for source: \" + source);\n return this;\n }\n\n // file already exists and is not empty\n if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {\n this.emit(\"complete\");\n return this;\n } else {\n let file = fs.createWriteStream(target, {'flags': 'a'});\n\n handler.get(source, (response) => {\n let size = response.headers['content-length']; // in bytes\n let prog = 0; // already downloaded\n let progCounts = 100; // how many progress events should be triggerd (1-100 %)\n let nextProg = (1/progCounts);\n \n response.on('data', (chunk) => {\n prog += chunk.length;\n file.write(chunk, 'binary');\n\n if ((prog / size) > nextProg) {\n this.emit('progress',prog / size);\n nextProg += (1 / progCounts);\n } \n });\n\n response.once('end', () => {\n file.end();\n this.emit('complete');\n }); \n\n }).on('error', (error) => {\n fs.unlink(target);\n this.emit(\"error\", \"Error while downloading: \" + error);\n });\n\n return this;\n } \n }\n\n cleanup(files:Array<File>, basePath?:string) {\n try {\n let localFiles = fs.readdirSync(basePath);\n Util.getFilesForCleanup(files, localFiles)\n .forEach((file) => {\n fs.unlinkSync(basePath + \"/\" + file);\n }); \n } catch (e) {\n }\n \n return this;\n }\n\n}","import { NodeFileHandler } from './file-handler/node-file-handler';\n\nexport default class Bsync {\n\n static configIpcMain(ipcMain: any, basePath: string) { \n \n ipcMain.on('bsync-download', (event, args) => {\n let nodeFileHander = new NodeFileHandler();\n nodeFileHander.download(args.source, basePath + \"/\" + args.target)\n .on('progress', (progress:number) => { event.sender.send('bsync-download-progress', progress); })\n .once('error', (error) => { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-error', error); })\n .once('complete', () => { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-complete'); });\n });\n\n ipcMain.on('bsync-cleanup', (event, args) => {\n let nodeFileHandler = new NodeFileHandler();\n nodeFileHandler.cleanup(args.files, basePath);\n event.sender.send('bsync-cleanup-complete');\n });\n\n }\n\n}"],"names":["fs.existsSync","fs.statSync","fs.createWriteStream","fs.unlink","fs.readdirSync","fs.unlinkSync","EventEmitter"],"mappings":"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"}
\ No newline at end of file
......
interface FileReplicator {
start(retries?:number) : void;
clear() : void;
cleanup() : void;
pushChanges(change: any) : void;
on(event:string, handler:(...params: any[]) => void) : FileReplicator;
once(event:string, handler:(...params: any[]) => void) : FileReplicator;
removeAllListeners() : FileReplicator;
}
declare var bsyncClient: {
CONFIG_TARGET_DIRECTORY : string ;
ServiceLocator : {
getConfig : () => {
getConfig : (key:string) => any;
setConfig : (key:string, value:any) => void;
hasConfig : (key:string) => boolean;
};
getFileReplicator : () => FileReplicator;
}
};
declare module "bsync-client" {
export = bsyncClient;
}
\ No newline at end of file
......@@ -3,6 +3,7 @@
"version": "1.0.0",
"description": "",
"main": "dist/browser-build.js",
"typings": "index.d.ts",
"scripts": {
"build": "npm run build:node && npm run build:browser",
"build:node": "rollup -c ./config/rollup.config.node.js",
......@@ -16,9 +17,6 @@
},
"author": "",
"license": "ISC",
"dependencies": {
"rxjs": "^5.0.2"
},
"devDependencies": {
"@types/jasmine": "^2.5.40",
"cordova": "^6.4.0",
......
#!/bin/bash
curl -X DELETE http://admin:admin@127.0.0.1:5984/pouch_test_db
rm -R ./.tmp
\ No newline at end of file
rm -rf ./.tmp
rm -rf ./.tmp-files
\ No newline at end of file
......
#!/bin/bash
rm -rf ./.tmp
rm -rf ./.tmp-files
curl -X DELETE http://admin:admin@127.0.0.1:5984/pouch_test_db
curl -X PUT http://admin:admin@127.0.0.1:5984/pouch_test_db
......
......@@ -7,15 +7,14 @@ echo "cordova $COMMAND $PLATFORM"
rollup --config ./config/rollup.config.cordova-test.js
cp ./spec/cordova-plugin-test/plugin.xml .tmp/plugin.xml
cp ./node_modules/rxjs/bundles/Rx.min.js .tmp/Rx.min.js
cd ..
rm -r ./bsync-client-test-app
rm -rf ./bsync-client-test-app
./bsync-client/node_modules/.bin/cordova create bsync-client-test-app
cd ./bsync-client-test-app
../bsync-client/node_modules/.bin/cordova platform add $PLATFORM
../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client
# ../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client
../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client/.tmp
../bsync-client/node_modules/.bin/cordova plugin add cordova-plugin-test-framework
......@@ -27,4 +26,4 @@ else
cordova emulate $PLATFORM
fi
rm -R ../bsync-client/.tmp
\ No newline at end of file
rm -rf ../bsync-client/.tmp
\ No newline at end of file
......
......@@ -5,8 +5,6 @@ import {TestFileHandler} from './file-handler/test-file-handler';
ServiceLocator.addFileHandler(ENV_UNKNOWN, new TestFileHandler());
import '../src/browser-main';
declare var emit:any;
const dbUrl = 'http://admin:admin@localhost:5984/pouch_test_db';
......@@ -49,32 +47,71 @@ describe("Integration tests with couchdb", () => {
it("Should successfully download several files", (done) => {
TestFileHandler.setErrorRate(0);
ServiceLocator.getFileReplicator().init();
let replicator = ServiceLocator.getFileReplicator();
let index = 0;
localDb.replicate.from(dbUrl)
.on('file-replicator-complete', event => {
replicator.clear();
replicator
.on('file-complete', () => {
index++;
})
.on('complete', () => {
.once('complete', () => {
expect(index).toEqual(3);
done();
});
localDb.replicate.from(dbUrl)
.once('complete', () => {
localDb.query('index_type/type',{
include_docs : true,
key : replicator.itemValue
}).then((res) => {
let docs = [];
for (let r of res.rows) {
docs.push(r.doc);
}
replicator.pushChanges(docs);
replicator.start();
});
});
});
it("Should trigger errors, but successfully download with retries", (done) => {
TestFileHandler.setErrorRate(0.8);
ServiceLocator.getFileReplicator().init();
let replicator = ServiceLocator.getFileReplicator();
let errors = 0;
localDb.replicate.from(dbUrl)
.on('file-replicator-error', event => {
replicator.clear();
replicator
.on('file-error', () => {
errors++;
})
.on('complete', () => {
.once('complete', () => {
expect(errors).toBeGreaterThanOrEqual(1);
done();
});
localDb.replicate.from(dbUrl)
.once('complete', () => {
localDb.query('index_type/type',{
include_docs : true,
key : replicator.itemValue
}).then((res) => {
let docs = [];
for (let r of res.rows) {
docs.push(r.doc);
}
replicator.pushChanges(docs);
replicator.start();
});
});
});
});
......
......@@ -5,14 +5,11 @@
version="1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<name>bsync cordova test</name>
<name>bsync test in cordova environment</name>
<license>Apache 2.0 License</license>
<js-module src="Rx.min.js" name="Rx">
<clobbers target="Rx" />
</js-module>
<js-module src="cordova-test-build.js" name="tests">
</js-module>
<dependency id="cordova-plugin-file-transfer" url="https://github.com/apache/cordova-plugin-file-transfer" commit="master" />
</plugin>
\ No newline at end of file
......
import { CordovaDownloader } from '../src/file-handler/cordova-file-handler';
import { CordovaFileHandler } from '../src/file-handler/cordova-file-handler';
declare var cordova;
exports.defineAutoTests = function() {
let createFilesHelper = (filenames:Array<string>, successCallback, errorCallback) => {
let index = 0;
let create = () => {
if (index < filenames.length) {
console.log("try creating file: ", filenames[index]);
createFileHelper(filenames[index], create, errorCallback);
index += 1;
} else {
successCallback();
}
};
create();
};
let createFileHelper = (filename, successCallback, errorCallback) => {
window['requestFileSystem'](window['LocalFileSystem'].TEMPORARY, 0, (fs) => {
fs.root.getFile(filename, { create: true, exclusive: false },(fileEntry) => {
fileEntry.createWriter((fileWriter) => {
fileWriter.onwriteend = function() {
console.log("file created", filename);
successCallback();
};
fileWriter.onerror = function (e) {
console.error("file error", e);
errorCallback(e);
};
fileWriter.write(new Blob(['some arbitrary file data'], { type: 'text/plain' }));
});
}, errorCallback);
}, errorCallback);
};
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
describe("Cordova downloader", () => {
let downloader = new CordovaDownloader();
let handler = new CordovaFileHandler();
it("should download sample image from https source and store with new name", (done) => {
let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg";
let target = cordova.file.dataDirectory + "full-moon.jpg";
let source = "https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg";
// let target = cordova.file.dataDirectory + "full-moon.jpg";
let target = "cdvfile://localhost/temporary/full-moon.jpg";
let lastProgress = 0;
downloader.download(source, target)
.subscribe(
(progress: number) => {
handler.download(source, target)
.on('progress', (progress: number) => {
expect(progress).toBeGreaterThan(lastProgress);
lastProgress = progress;
} ,
(error:any) => {
}).once('error', (error:any) => {
fail();
} ,
() => {
}).once('complete', () => {
expect(lastProgress).toEqual(1);
window['resolveLocalFileSystemURL'](target, (entry:any) => {
......@@ -31,9 +64,31 @@ exports.defineAutoTests = function() {
expect(entry.name).toEqual("full-moon.jpg");
done();
});
}
);
});
});
it('should cleanup successfully', (done) => {
createFilesHelper(['file-1', 'file-2', 'file-3'], () => {
console.log("files are created, now start with cleanup");
handler.once('cleanup-complete', (files) => {
console.log(files);
expect(files.length).toBeGreaterThan(1);
done();
});
handler.once('cleanup-error', (files) => {
fail('cleanup error');
});
handler.cleanup([
{ source: '', target: 'file-1' } ,
{ source: '', target: 'file-2' }
], 'cdvfile://localhost/temporary/');
}, (error) => {
console.error(error);
fail('error while creating files');
});
});
});
......
import { Observable, Subscriber } from 'rxjs';
import { EventEmitter } from 'events';
import { FileHandler } from '../../src/api/file-handler';
export class TestFileHandler implements FileHandler {
export class TestFileHandler extends EventEmitter implements FileHandler {
protected static errorRate:number = 0;
......@@ -9,27 +9,30 @@ export class TestFileHandler implements FileHandler {
TestFileHandler.errorRate = rate;
}
download(source:string, target:string) : Observable<number> {
return Observable.create((subscriber:Subscriber<number>) => {
cleanup() { return this; }
download(source:string, target:string) {
let random = Math.random();
let error:boolean = random < TestFileHandler.errorRate;
let counter = 1;
if (error) {
subscriber.error("random error triggered");
return;
}
setTimeout(() => {
this.emit("error", "random error triggered");
},200);
} else {
let interval = setInterval(() => {
if (counter < 4) {
subscriber.next(counter * 25);
this.emit('progress', counter * 25);
} else {
subscriber.complete();
this.emit('complete');
clearInterval(interval);
}
++counter;
}, 10);
});
}
return this;
}
}
\ No newline at end of file
......
export * from './test/file-handler/node-file-handler';
export * from './test/file-replicator';
export * from './test/util';
\ No newline at end of file
......
......@@ -7,6 +7,10 @@ describe("Node Downloader", () => {
let nodeFileHandler = new NodeFileHandler();
beforeEach(() => {
nodeFileHandler.removeAllListeners();
});
it("should retrieve right handler", () => {
let httpHandler = nodeFileHandler.selectProtocol("http://someurl.com/image.jpg");
......@@ -23,27 +27,26 @@ describe("Node Downloader", () => {
it("should download sample image from https source and store with new name", (done) => {
let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg";
let target = ".tmp/full-moon.jpg";
let target = "./.tmp/full-moon-" + (new Date()).getTime() + ".jpg";
let lastProgress = 0;
nodeFileHandler.download(source, target)
.subscribe(
(progress: number) => {
nodeFileHandler
.on('progress', (progress: number) => {
expect(progress).toBeGreaterThan(lastProgress);
lastProgress = progress;
} ,
(error:any) => {} ,
() => {
})
.once('error', (error) => {})
.once('complete', () => {
expect(lastProgress).toEqual(1);
expect(fs.existsSync(target)).toBeTruthy();
done();
}
);
})
.download(source, target);
});
it('should not download if file with same name exists and bytesize > 0', (done) => {
let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg";
let target = ".tmp/full-moon-sensless.jpg";
let target = "./.tmp/full-moon-sensless.jpg";
let lastProgress = 0;
let file = fs.createWriteStream(target, {'flags': 'a'});
......@@ -51,18 +54,32 @@ describe("Node Downloader", () => {
file.write(new Buffer(dummyData));
file.end(() => {
nodeFileHandler.download(source, target)
.subscribe(
() => { fail("progress should not be called"); } ,
() => {} ,
() => {
nodeFileHandler
.on('progress', () => { fail("progress should not be called"); })
.once('error', () => {})
.once('complete', () => {
expect(fs.existsSync(target)).toBeTruthy();
done();
}
);
})
.download(source, target);
});
});
it('should correctly cleanup files', () => {
let basePath = "./.tmp-files";
fs.mkdirSync(basePath);
fs.writeFileSync(basePath + "/file1", "some data for file 1");
fs.writeFileSync(basePath + "/file2", "some data for file 2");
fs.writeFileSync(basePath + "/file3", "some data for file 3");
fs.writeFileSync(basePath + "/file4", "some data for file 4");
nodeFileHandler.cleanup([
{ source : '' , target : 'file1' },
{ source : '' , target : 'file2' }], basePath);
let files = fs.readdirSync(basePath);
expect(files.length).toEqual(2);
});
});
\ No newline at end of file
......
import { FileReplicator } from '../../src/file-replicator';
describe("File Replicator", () => {
let fileReplicator = new FileReplicator();
let change = {
docs : [
let change = [
{ language: 'de', type : "asset", source : "http://someplace.com/icon.jpg" , target : "icon.jpg" } ,
{ language: 'de', type : "asset", source : "http://sampleuri.com/image.png" } ,
{ language: 'en', type : "asset", source : "https://secureasset.com/asset.mp3" , target : "music.mp3" }
]
};
];
beforeEach(() => {
fileReplicator.init();
fileReplicator.clear();
});
it("should contain several assets", () => {
......@@ -23,7 +20,7 @@ describe("File Replicator", () => {
});
it("should get correct asset names", () => {
let files = fileReplicator.prepareFiles(change.docs);
let files = fileReplicator.prepareFiles(change);
expect(files[0].target).toEqual("icon.jpg");
expect(files[1].target).toEqual("bsync_707608502");
......@@ -38,7 +35,7 @@ describe("File Replicator", () => {
return false;
};
let files = fileReplicator.prepareFiles(change.docs);
let files = fileReplicator.prepareFiles(change);
expect(files.length).toEqual(2);
expect(files[0].target).toEqual("icon.jpg");
......
import { Util } from '../../src/util';
describe('Util', () => {
let files = [
{ source : '' , target : 'file-1'} ,
{ source : '' , target : 'file-2'} ,
{ source : '' , target : 'file-3'} ,
];
it('should show files to remove', () => {
let cleanupFiles = Util.getFilesForCleanup(files, ['file-1','file-4']);
expect(cleanupFiles[0]).toEqual('file-4');
});
});
\ No newline at end of file
import { Observable } from 'rxjs/Observable';
import { File } from './file';
export interface FileHandler {
......@@ -8,6 +8,17 @@ export interface FileHandler {
* - if the download is in progress: trigger next (0-1 progress for percent of download)
* - if the download enters any error condition, trigger error and an already downloaded part of the file
*/
download(source:string, target:string) : Observable<number>;
download(source:string, target:string) : FileHandler;
/**
* Remove all files, which are not inside the files array from local storage
*/
cleanup(files: Array<File>, basePath?: string);
on(event:string, handler:(...params: any[]) => void) : FileHandler;
once(event:string, handler:(...params: any[]) => void) : FileHandler;
removeAllListeners() : FileHandler;
}
\ No newline at end of file
......
import { EventEmitter } from 'events';
import { ServiceLocator } from './service-locator';
export * from './service-locator';
export function loadBsyncPlugin (PouchDB) {
let pouchReplicate = PouchDB.replicate;
PouchDB.plugin((PouchDB) => {
PouchDB.replicate = function() {
let eventEmitter = new EventEmitter();
let emitter = pouchReplicate.apply(this, arguments);
let replicator = ServiceLocator.getFileReplicator();
let db = arguments[1];
replicator.once('final', event => {
eventEmitter.emit('complete');
eventEmitter.removeAllListeners();
});
replicator.on('error', event => {
eventEmitter.emit('file-replicator-error', event);
});
replicator.on('complete', event => {
eventEmitter.emit('file-replicator-complete', event);
});
replicator.on('progress', event => {
eventEmitter.emit('file-replicator-progress', event);
});
emitter.once('change', info => {
eventEmitter.emit('change', info);
});
emitter.once('complete', info => {
db.query('index_type/type',{
include_docs : true,
key : replicator.itemValue
}).then((res) => {
let docs = { docs : [] };
for (let r of res.rows) {
docs.docs.push(r.doc);
}
replicator.pushChanges(docs);
replicator.start();
}).catch(error => {
eventEmitter.emit('error', error);
});
});
emitter.once('error', (error) => {
eventEmitter.emit('error', error);
});
return eventEmitter;
};
});
};
if (typeof window !== 'undefined' && window['PouchDB']) {
loadBsyncPlugin(window['PouchDB']);
}
export * from './config';
......
......@@ -5,24 +5,26 @@ export const CONFIG_ITEM_TARGET_ATTRIBUTE = "itemTargetAttribute";
export const CONFIG_ITEM_VALIDATOR = "itemValidator";
export const CONFIG_RETRY_TIMEOUT = "retryTimeout";
export const CONFIG_FILE_HANDLER = "fileHandler";
export const CONFIG_TARGET_DIRECTORY = "targetDirectory";
export class Config {
protected config:any = {};
hasConfig(key:string) {
hasConfig(key:string) : boolean {
if (this.config[key]) {
return true;
}
return false;
}
getConfig(key:string) {
getConfig(key:string) : any {
return this.config[key];
}
setConfig(key:string, value:any) {
setConfig(key:string, value:any) : Config {
this.config[key] = value;
return this;
}
}
\ No newline at end of file
......
import { Util } from './../util';
import { EventEmitter } from 'events';
import { FileHandler } from '../api/file-handler';
import { File } from '../api/file';
declare var Rx;
export class CordovaDownloader implements FileHandler {
download(source:string, target:string) : Rx.Observable<number> {
return Rx.Observable.create((subscriber:Rx.Subscriber<number>) => {
if (!window['FileTransfer']) {
subscriber.error("Cordova FileTransfer object undefined");
}
export class CordovaFileHandler extends EventEmitter implements FileHandler {
triggerFileTransfer(source:string, target:string) {
let fileTransfer = new window['FileTransfer']();
fileTransfer.onprogress = (progress:ProgressEvent) => {
subscriber.next(progress.loaded / progress.total);
this.emit('progress', progress.loaded / progress.total);
};
fileTransfer.download(
source ,
target ,
(entry:any) => {
subscriber.complete();
this.emit('complete', entry);
} ,
(error:any) => {
subscriber.error(error);
this.emit('error', error);
},
true
);
}
download(source:string, target:string) {
if (!window['FileTransfer']) {
this.emit('error','Cordova FileTransfer object undefined');
}
window['resolveLocalFileSystemURL'](target, (entry:any) => {
entry.getMetadata((metadata) => {
if (metadata.size > 0) {
this.emit('complete', entry);
} else {
// file empty trigger transfer
this.triggerFileTransfer(source,target);
}
}, () => {
// cannot read metadata trigger transfer
this.triggerFileTransfer(source,target);
});
}, () => {
// file not found, so download it
this.triggerFileTransfer(source,target);
});
return this;
}
cleanup(files:Array<File>, basePath:string) : Promise<void> {
let filesForCleanup = [];
return new Promise<void>((resolve, reject) => {
if (window['resolveLocalFileSystemURL']) {
window['resolveLocalFileSystemURL'](basePath, (entry) => {
let reader = entry.createReader();
reader.readEntries((entries) => {
for (let e of entries) {
if (e && e.isFile) {
if (Util.getFileIndex(files, e.name) < 0) {
filesForCleanup.push(e);
}
}
}
let index = 0;
let error = false;
let cleanupError = (error) => {
this.emit('cleanup-error', error);
reject();
error = true;
};
let cleanupNext = () => {
if (index < filesForCleanup.length && !error) {
filesForCleanup[index].remove(cleanupNext, cleanupError);
index += 1;
} else if (!error) {
this.emit('cleanup-complete', filesForCleanup);
resolve();
}
};
cleanupNext();
}, (error) => { this.emit('cleanup-error', error); reject(); });
});
}
});
}
......
import { Observable, Subscriber } from 'rxjs';
import { EventEmitter } from 'events';
import { FileHandler } from '../api/file-handler';
import { File } from '../api/file';
export class ElectronFileHandler implements FileHandler {
export class ElectronFileHandler extends EventEmitter implements FileHandler {
constructor (private ipcRenderer:any) {
super();
}
download(source:string, target:string) : Observable<number> {
return Observable.create((subscriber:Subscriber<number>) => {
download(source:string, target:string) {
this.ipcRenderer.once('bsync-download-complete', () => {
this.ipcRenderer.removeAllListeners('bsync-download-progress');
this.ipcRenderer.removeAllListeners('bsync-download-error');
subscriber.complete();
this.emit('complete');
});
this.ipcRenderer.on('bsync-download-progress', (progress:number) => {
subscriber.next(progress);
this.emit('progress', progress);
});
this.ipcRenderer.once('bsync-download-error', (error:any) => {
this.ipcRenderer.removeAllListeners('bsync-download-progress');
this.ipcRenderer.removeAllListeners('bsync-download-complete');
subscriber.error(error);
this.emit('error', error);
});
this.ipcRenderer.send('bsync-download', {
source : source ,
target : target
});
return this;
}
cleanup(files:Array<File>) : Promise<void> {
return new Promise<void>((resolve, reject) => {
this.ipcRenderer.once('bsync-cleanup-complete', () => {
this.emit('cleanup-complete');
resolve();
});
this.ipcRenderer.send('bsync-cleanup', files);
});
}
......
import { Observable } from 'rxjs/Observable';
import { Subscriber } from 'rxjs/Subscriber';
import { Util } from './../util';
import { EventEmitter } from 'events';
import { FileHandler } from '../api/file-handler';
import { File } from '../api/file';
import * as http from 'http';
import * as https from 'https';
import * as fs from 'fs';
export class NodeFileHandler implements FileHandler {
export class NodeFileHandler extends EventEmitter implements FileHandler {
selectProtocol(url:string) : any {
if (url.search(/^http:\/\//) === 0) {
......@@ -17,23 +18,20 @@ export class NodeFileHandler implements FileHandler {
}
}
download(source:string, target:string) : Observable<number> {
download(source:string, target:string) {
let handler = this.selectProtocol(source);
return Observable.create((subscriber:Subscriber<number>) => {
if (!handler) {
subscriber.error("No handler for source: " + source);
return;
this.emit("error","No handler for source: " + source);
return this;
}
// file already exists and is not empty
if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
subscriber.complete();
return;
}
this.emit("complete");
return this;
} else {
let file = fs.createWriteStream(target, {'flags': 'a'});
handler.get(source, (response) => {
......@@ -47,23 +45,36 @@ export class NodeFileHandler implements FileHandler {
file.write(chunk, 'binary');
if ((prog / size) > nextProg) {
subscriber.next(prog / size);
this.emit('progress',prog / size);
nextProg += (1 / progCounts);
}
});
response.on('end', () => {
response.once('end', () => {
file.end();
subscriber.complete();
this.emit('complete');
});
}).on('error', (error) => {
fs.unlink(target);
subscriber.error("Error while downloading: " + error);
this.emit("error", "Error while downloading: " + error);
});
return this;
}
}
cleanup(files:Array<File>, basePath?:string) {
try {
let localFiles = fs.readdirSync(basePath);
Util.getFilesForCleanup(files, localFiles)
.forEach((file) => {
fs.unlinkSync(basePath + "/" + file);
});
} catch (e) {
}
return this;
}
}
\ No newline at end of file
......
import {FileHandler} from './api/file-handler';
import {File} from './api/file';
import {Util} from './util';
import {EventEmitter} from 'events';
import { FileHandler } from './api/file-handler';
import { File } from './api/file';
import { Util } from './util';
import { EventEmitter } from 'events';
export class FileReplicator extends EventEmitter {
......@@ -9,46 +9,52 @@ export class FileReplicator extends EventEmitter {
super();
}
protected _files:Array<File> = [];
protected _files: Array<File> = [];
protected _itemValidator: (item:any) => boolean = null;
protected _fileHandler:FileHandler = null;
protected _retryTimeout:number = 0;
protected _itemValidator: (item: any) => boolean = null;
protected _fileHandler: FileHandler = null;
protected _retryTimeout: number = 100;
protected _retries: number = 10;
protected _itemKey = "type";
protected _itemValue = "asset";
protected _itemSourceAttribute = "source";
protected _itemTargetAttribute = "target";
protected _targetDirectory = "";
get files(): Array<File> {
return this._files;
}
set fileHandler (handler:FileHandler) {
set fileHandler(handler: FileHandler) {
this._fileHandler = handler;
}
set retryTimeout (timeout:number) {
get fileHandler() : FileHandler {
return this._fileHandler;
}
set retryTimeout(timeout: number) {
this._retryTimeout = timeout;
}
set itemValidator(validator:(item:any) => boolean) {
set itemValidator(validator: (item: any) => boolean) {
this._itemValidator = validator;
}
set itemKey(key:string) {
set itemKey(key: string) {
this._itemKey = key;
}
set itemValue(value:string) {
set itemValue(value: string) {
this._itemValue = value;
}
set itemSourceAttribute(sourceAttribute:string) {
set itemSourceAttribute(sourceAttribute: string) {
this._itemSourceAttribute = sourceAttribute;
}
set itemTargetAttribute(targetAttribute:string) {
set itemTargetAttribute(targetAttribute: string) {
this._itemTargetAttribute = targetAttribute;
}
......@@ -68,18 +74,26 @@ export class FileReplicator extends EventEmitter {
return this._itemTargetAttribute;
}
init(files: Array<File> = []) {
set targetDirectory(targetDirectory: string) {
this._targetDirectory = targetDirectory;
}
get targetDirectory() {
return this._targetDirectory;
}
clear(files: Array<File> = []) {
this._files = files;
}
/**
* change from pouchdb replicate
*/
pushChanges(change:any) {
let items:Array<any> = [];
pushChanges(docs: Array<any>) {
let items: Array<any> = [];
if (change && change.docs && change.docs.length > 0) {
for (let item of change.docs) {
if (docs && docs.length > 0) {
for (let item of docs) {
if (item[this._itemKey] && item[this._itemKey] === this._itemValue) {
items.push(item);
}
......@@ -93,35 +107,35 @@ export class FileReplicator extends EventEmitter {
}
}
downloadFiles(files:Array<File>, fileHandler:FileHandler, index:number = 0) {
downloadFiles(files: Array<File>, fileHandler: FileHandler, index: number = 0) {
if (index >= files.length) {
return;
}
this.emit('start', { progress: 0, index : index, length : files.length });
this.emit('start', { progress: 0, index: index, length: files.length });
fileHandler
.download(files[index].source, files[index].target)
.subscribe(
progress => {
this.emit('progress', { progress : progress, index : index, length : files.length })
} ,
error => {
this.emit('error', { progress : 0, index : index, length : files.length, error: error });
} ,
() => {
this.emit('complete', { progress : 100 , index : index, length : files.length });
this.downloadFiles(files, fileHandler, index+1);
}
);
}
prepareFiles(items: Array<any>) : Array<File> {
.on('progress', (progress) => {
this.emit('file-progress', { progress: progress, index: index, length: files.length })
})
.once('error', error => {
this.emit('file-error', { progress: 0, index: index, length: files.length, error: error });
fileHandler.removeAllListeners();
})
.once('complete', () => {
this.emit('file-complete', { progress: 100, index: index, length: files.length });
fileHandler.removeAllListeners();
this.downloadFiles(files, fileHandler, index + 1);
})
.download(files[index].source, this.targetDirectory + files[index].target);
}
prepareFiles(items: Array<any>): Array<File> {
let output = [];
for (let item of items) {
if (item[this._itemSourceAttribute] && (!this._itemValidator || this._itemValidator(item))) {
let file = { source : item[this._itemSourceAttribute] , target : '' };
let file = { source: item[this._itemSourceAttribute], target: '' };
if (item[this._itemTargetAttribute]) {
file.target = item[this._itemTargetAttribute];
......@@ -136,29 +150,47 @@ export class FileReplicator extends EventEmitter {
return output;
}
start() {
this.on('complete', (event:any) => {
start(retries:number = 10) {
this._retries = retries;
this.on('file-complete', (event: any) => {
if ((event.index + 1) >= event.length) {
this.replicationFinalized(event.index);
}
});
this.on('error', (event:any) => {
this.on('file-error', (event: any) => {
this.replicationFinalized(event.index);
});
if (this._fileHandler && this._files.length > 0) {
this.downloadFiles(this._files, this._fileHandler);
} else {
this.emit('complete');
}
}
cleanup() {
this.fileHandler
.cleanup(this._files, this._targetDirectory)
.then(() => {
this.emit('cleanup-complete');
}).catch(() => {
this.emit('cleanup-error');
});
}
replicationFinalized(lastIndex:number) {
if (lastIndex+1 >= this._files.length) { // all finished
this._files = [];
this.emit('final');
} else if (this._retryTimeout > 0) { // restart after last success
this._files.splice(0,lastIndex);
replicationFinalized(lastIndex: number) {
if (lastIndex + 1 >= this._files.length) { // all finished
this.emit('complete');
} else if (this._retries > 0) { // restart after last success
this._files.splice(0, lastIndex);
setTimeout(() => {
this._retries =- 1;
this.downloadFiles(this._files, this._fileHandler);
}, this._retryTimeout);
} else {
this.emit('error');
}
}
......
......@@ -2,17 +2,22 @@ import { NodeFileHandler } from './file-handler/node-file-handler';
export default class Bsync {
static configIpcMain(ipcMain: any, downloadDir:string) {
let nodeFileHander = new NodeFileHandler();
static configIpcMain(ipcMain: any, basePath: string) {
ipcMain.on('bsync-download', (event, args) => {
nodeFileHander.download(args.source, downloadDir + args.target)
.subscribe(
(progress:number) => { event.sender.send('bsync-download-progress', progress); } ,
(error:any) => { event.sender.send('bsync-download-error', error); } ,
() => { event.sender.send('bsync-download-complete'); }
);
let nodeFileHander = new NodeFileHandler();
nodeFileHander.download(args.source, basePath + "/" + args.target)
.on('progress', (progress:number) => { event.sender.send('bsync-download-progress', progress); })
.once('error', (error) => { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-error', error); })
.once('complete', () => { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-complete'); });
});
ipcMain.on('bsync-cleanup', (event, args) => {
let nodeFileHandler = new NodeFileHandler();
nodeFileHandler.cleanup(args.files, basePath);
event.sender.send('bsync-cleanup-complete');
});
}
}
\ No newline at end of file
......
import {FileHandler} from './api/file-handler';
import {ElectronFileHandler} from './file-handler/electron-file-handler';
import {CordovaDownloader} from './file-handler/cordova-file-handler';
import {CordovaFileHandler} from './file-handler/cordova-file-handler';
import {FileReplicator} from './file-replicator';
import {
Config,
......@@ -8,7 +8,8 @@ import {
CONFIG_ITEM_KEY,
CONFIG_ITEM_VALUE,
CONFIG_ITEM_TARGET_ATTRIBUTE,
CONFIG_ITEM_SOURCE_ATTRIBUTE
CONFIG_ITEM_SOURCE_ATTRIBUTE,
CONFIG_TARGET_DIRECTORY
} from './config';
export const ENV_ELECTRON = "electron";
......@@ -56,7 +57,7 @@ export class ServiceLocator {
}
if (environment === ENV_CORDOVA) {
return new CordovaDownloader();
return new CordovaFileHandler();
}
return null;
......@@ -64,10 +65,9 @@ export class ServiceLocator {
static getFileReplicator() : FileReplicator {
if (!ServiceLocator.fileReplicator) {
ServiceLocator.fileReplicator = new FileReplicator();
ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler();
}
if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) {
ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT);
......@@ -84,6 +84,8 @@ export class ServiceLocator {
if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) {
ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE);
}
if (ServiceLocator.getConfig().hasConfig(CONFIG_TARGET_DIRECTORY)) {
ServiceLocator.fileReplicator.targetDirectory = ServiceLocator.getConfig().getConfig(CONFIG_TARGET_DIRECTORY);
}
return ServiceLocator.fileReplicator;
......
import { File } from './api/file';
export class Util {
static getNameHash(path:string) {
......@@ -7,4 +9,36 @@ export class Util {
return "bsync_" + Math.abs(r);
}
/**
* index >= 0, localFile is in files
* index < 0, localFile is not in files
*/
static getFileIndex(files:Array<File>, localFile:string) : number {
for (let i = 0; i < files.length; i++) {
if (localFile == files[i].target) {
return i;
}
}
return -1;
}
static getFilesForCleanup(files:Array<File>, localFiles:Array<string>) : Array<string> {
let filesForCleanup = [];
for (let localFile of localFiles) {
let index = -1;
index = Util.getFileIndex(files, localFile);
if (index < 0) {
filesForCleanup.push(localFile);
} else {
// splice for performance improvement only
files.splice(index,1);
}
}
return filesForCleanup;
}
}
\ No newline at end of file
......