Stefan Huber

last update

...@@ -4,21 +4,64 @@ Allows downloading of files referenced by a http/https URI inside a couchdb/pouc ...@@ -4,21 +4,64 @@ Allows downloading of files referenced by a http/https URI inside a couchdb/pouc
4 4
5 # Usage 5 # Usage
6 6
7 -### In cordova projects 7 +## Use it with pouchdb
8 8
9 -### In electron projects 9 +```typescript
10 +import {ServiceLocator} from 'bsync-client/dist/browser-build';
10 11
11 -Within the main process bsync needs to be integrated an initiated. 12 +ServiceLocator.getConfig().setConfig('itemKey', 'type');
13 +ServiceLocator.getConfig().setConfig('itemValue', 'asset');
12 14
13 - import {Bsync} from 'bsync'; 15 +let localDb = new PouchDB('local-pouch-db');
14 - Bsync.init(ipcMain, filePath); 16 +let fileReplicator = ServiceLocator.getFileReplicator();
15 17
16 -# Testing (Browser) 18 +localDb.put({
19 + _id : "_design/index_type",
20 + views : {
21 + type : {
22 + map : function(doc) {
23 + if (doc[fileReplicator.itemKey]) { emit(doc[fileReplicator.itemKey]); }
24 + }.toString()
25 + }
26 + }
27 +});
28 +
29 +fileReplicator.once('complete', () => {
30 + // All file are downloaded
31 +});
32 +
33 +db.query('index_type/type',{
34 + include_docs : true,
35 + key : fileReplicator.itemValue
36 +}).then((res) => {
37 + let docs = { docs : [] };
38 + for (let r of res.rows) {
39 + docs.docs.push(r.doc);
40 + }
41 +
42 + fileReplicator.pushChanges(docs);
43 + fileReplicator.start();
44 +});
45 +```
46 +
47 +
48 +## In electron projects
49 +
50 +Within the `main process` bsync needs to be integrated an initiated.
51 +
52 +```typescript
53 +import {Bsync} from 'bsync';
54 +Bsync.init(ipcMain, filePath);
55 +```
56 +
57 +# Testing (Browser/Node)
17 58
18 `npm test` 59 `npm test`
19 60
20 # Testing (Cordova) 61 # Testing (Cordova)
21 62
63 +`npm run test:cordova`
64 +
22 65
23 66
24 67
......
...@@ -8,10 +8,6 @@ export default { ...@@ -8,10 +8,6 @@ export default {
8 8
9 format: 'umd', 9 format: 'umd',
10 10
11 - globals: {
12 - 'rxjs' : 'Rx'
13 - },
14 -
15 plugins: [ 11 plugins: [
16 typescript() , 12 typescript() ,
17 globals(), 13 globals(),
......
...@@ -9,13 +9,13 @@ export default { ...@@ -9,13 +9,13 @@ export default {
9 entry: './src/browser-main.ts', 9 entry: './src/browser-main.ts',
10 dest: './dist/browser-build.js', 10 dest: './dist/browser-build.js',
11 11
12 - format: 'cjs', 12 + format: 'umd',
13 13
14 sourceMap: true , 14 sourceMap: true ,
15 15
16 plugins: [ 16 plugins: [
17 typescript(), 17 typescript(),
18 - // globals(), 18 + globals(),
19 - // builtins() 19 + builtins()
20 ] 20 ]
21 }; 21 };
...\ No newline at end of file ...\ No newline at end of file
......
1 import typescript from 'rollup-plugin-typescript'; 1 import typescript from 'rollup-plugin-typescript';
2 +import builtins from 'rollup-plugin-node-builtins';
3 +import globals from 'rollup-plugin-node-globals';
2 4
3 export default { 5 export default {
4 6
...@@ -10,6 +12,8 @@ export default { ...@@ -10,6 +12,8 @@ export default {
10 format: 'cjs', 12 format: 'cjs',
11 13
12 plugins: [ 14 plugins: [
13 - typescript() 15 + typescript(),
16 + globals(),
17 + builtins()
14 ] 18 ]
15 }; 19 };
...\ No newline at end of file ...\ No newline at end of file
......
1 -'use strict'; 1 +(function (global, factory) {
2 + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
3 + typeof define === 'function' && define.amd ? define(['exports'], factory) :
4 + (factory((global.bsync = global.bsync || {})));
5 +}(this, (function (exports) { 'use strict';
2 6
3 -Object.defineProperty(exports, '__esModule', { value: true }); 7 +var domain;
8 +
9 +// This constructor is used to store event handlers. Instantiating this is
10 +// faster than explicitly calling `Object.create(null)` to get a "clean" empty
11 +// object (tested with v8 v4.9).
12 +function EventHandlers() {}
13 +EventHandlers.prototype = Object.create(null);
14 +
15 +function EventEmitter() {
16 + EventEmitter.init.call(this);
17 +}
18 +EventEmitter.usingDomains = false;
19 +
20 +EventEmitter.prototype.domain = undefined;
21 +EventEmitter.prototype._events = undefined;
22 +EventEmitter.prototype._maxListeners = undefined;
23 +
24 +// By default EventEmitters will print a warning if more than 10 listeners are
25 +// added to it. This is a useful default which helps finding memory leaks.
26 +EventEmitter.defaultMaxListeners = 10;
27 +
28 +EventEmitter.init = function() {
29 + this.domain = null;
30 + if (EventEmitter.usingDomains) {
31 + // if there is an active domain, then attach to it.
32 + if (domain.active && !(this instanceof domain.Domain)) {
33 + this.domain = domain.active;
34 + }
35 + }
36 +
37 + if (!this._events || this._events === Object.getPrototypeOf(this)._events) {
38 + this._events = new EventHandlers();
39 + this._eventsCount = 0;
40 + }
41 +
42 + this._maxListeners = this._maxListeners || undefined;
43 +};
44 +
45 +// Obviously not all Emitters should be limited to 10. This function allows
46 +// that to be increased. Set to zero for unlimited.
47 +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {
48 + if (typeof n !== 'number' || n < 0 || isNaN(n))
49 + throw new TypeError('"n" argument must be a positive number');
50 + this._maxListeners = n;
51 + return this;
52 +};
53 +
54 +function $getMaxListeners(that) {
55 + if (that._maxListeners === undefined)
56 + return EventEmitter.defaultMaxListeners;
57 + return that._maxListeners;
58 +}
59 +
60 +EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
61 + return $getMaxListeners(this);
62 +};
63 +
64 +// These standalone emit* functions are used to optimize calling of event
65 +// handlers for fast cases because emit() itself often has a variable number of
66 +// arguments and can be deoptimized because of that. These functions always have
67 +// the same number of arguments and thus do not get deoptimized, so the code
68 +// inside them can execute faster.
69 +function emitNone(handler, isFn, self) {
70 + if (isFn)
71 + handler.call(self);
72 + else {
73 + var len = handler.length;
74 + var listeners = arrayClone(handler, len);
75 + for (var i = 0; i < len; ++i)
76 + listeners[i].call(self);
77 + }
78 +}
79 +function emitOne(handler, isFn, self, arg1) {
80 + if (isFn)
81 + handler.call(self, arg1);
82 + else {
83 + var len = handler.length;
84 + var listeners = arrayClone(handler, len);
85 + for (var i = 0; i < len; ++i)
86 + listeners[i].call(self, arg1);
87 + }
88 +}
89 +function emitTwo(handler, isFn, self, arg1, arg2) {
90 + if (isFn)
91 + handler.call(self, arg1, arg2);
92 + else {
93 + var len = handler.length;
94 + var listeners = arrayClone(handler, len);
95 + for (var i = 0; i < len; ++i)
96 + listeners[i].call(self, arg1, arg2);
97 + }
98 +}
99 +function emitThree(handler, isFn, self, arg1, arg2, arg3) {
100 + if (isFn)
101 + handler.call(self, arg1, arg2, arg3);
102 + else {
103 + var len = handler.length;
104 + var listeners = arrayClone(handler, len);
105 + for (var i = 0; i < len; ++i)
106 + listeners[i].call(self, arg1, arg2, arg3);
107 + }
108 +}
109 +
110 +function emitMany(handler, isFn, self, args) {
111 + if (isFn)
112 + handler.apply(self, args);
113 + else {
114 + var len = handler.length;
115 + var listeners = arrayClone(handler, len);
116 + for (var i = 0; i < len; ++i)
117 + listeners[i].apply(self, args);
118 + }
119 +}
4 120
5 -var events = require('events'); 121 +EventEmitter.prototype.emit = function emit(type) {
6 -var rxjs = require('rxjs'); 122 + var er, handler, len, args, i, events, domain;
123 + var needDomainExit = false;
124 + var doError = (type === 'error');
125 +
126 + events = this._events;
127 + if (events)
128 + doError = (doError && events.error == null);
129 + else if (!doError)
130 + return false;
131 +
132 + domain = this.domain;
133 +
134 + // If there is no 'error' event listener then throw.
135 + if (doError) {
136 + er = arguments[1];
137 + if (domain) {
138 + if (!er)
139 + er = new Error('Uncaught, unspecified "error" event');
140 + er.domainEmitter = this;
141 + er.domain = domain;
142 + er.domainThrown = false;
143 + domain.emit('error', er);
144 + } else if (er instanceof Error) {
145 + throw er; // Unhandled 'error' event
146 + } else {
147 + // At least give some kind of context to the user
148 + var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
149 + err.context = er;
150 + throw err;
151 + }
152 + return false;
153 + }
154 +
155 + handler = events[type];
156 +
157 + if (!handler)
158 + return false;
159 +
160 + var isFn = typeof handler === 'function';
161 + len = arguments.length;
162 + switch (len) {
163 + // fast cases
164 + case 1:
165 + emitNone(handler, isFn, this);
166 + break;
167 + case 2:
168 + emitOne(handler, isFn, this, arguments[1]);
169 + break;
170 + case 3:
171 + emitTwo(handler, isFn, this, arguments[1], arguments[2]);
172 + break;
173 + case 4:
174 + emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
175 + break;
176 + // slower
177 + default:
178 + args = new Array(len - 1);
179 + for (i = 1; i < len; i++)
180 + args[i - 1] = arguments[i];
181 + emitMany(handler, isFn, this, args);
182 + }
183 +
184 + if (needDomainExit)
185 + domain.exit();
186 +
187 + return true;
188 +};
189 +
190 +function _addListener(target, type, listener, prepend) {
191 + var m;
192 + var events;
193 + var existing;
194 +
195 + if (typeof listener !== 'function')
196 + throw new TypeError('"listener" argument must be a function');
197 +
198 + events = target._events;
199 + if (!events) {
200 + events = target._events = new EventHandlers();
201 + target._eventsCount = 0;
202 + } else {
203 + // To avoid recursion in the case that type === "newListener"! Before
204 + // adding it to the listeners, first emit "newListener".
205 + if (events.newListener) {
206 + target.emit('newListener', type,
207 + listener.listener ? listener.listener : listener);
208 +
209 + // Re-assign `events` because a newListener handler could have caused the
210 + // this._events to be assigned to a new object
211 + events = target._events;
212 + }
213 + existing = events[type];
214 + }
215 +
216 + if (!existing) {
217 + // Optimize the case of one listener. Don't need the extra array object.
218 + existing = events[type] = listener;
219 + ++target._eventsCount;
220 + } else {
221 + if (typeof existing === 'function') {
222 + // Adding the second element, need to change to array.
223 + existing = events[type] = prepend ? [listener, existing] :
224 + [existing, listener];
225 + } else {
226 + // If we've already got an array, just append.
227 + if (prepend) {
228 + existing.unshift(listener);
229 + } else {
230 + existing.push(listener);
231 + }
232 + }
233 +
234 + // Check for listener leak
235 + if (!existing.warned) {
236 + m = $getMaxListeners(target);
237 + if (m && m > 0 && existing.length > m) {
238 + existing.warned = true;
239 + var w = new Error('Possible EventEmitter memory leak detected. ' +
240 + existing.length + ' ' + type + ' listeners added. ' +
241 + 'Use emitter.setMaxListeners() to increase limit');
242 + w.name = 'MaxListenersExceededWarning';
243 + w.emitter = target;
244 + w.type = type;
245 + w.count = existing.length;
246 + emitWarning(w);
247 + }
248 + }
249 + }
250 +
251 + return target;
252 +}
253 +function emitWarning(e) {
254 + typeof console.warn === 'function' ? console.warn(e) : console.log(e);
255 +}
256 +EventEmitter.prototype.addListener = function addListener(type, listener) {
257 + return _addListener(this, type, listener, false);
258 +};
259 +
260 +EventEmitter.prototype.on = EventEmitter.prototype.addListener;
261 +
262 +EventEmitter.prototype.prependListener =
263 + function prependListener(type, listener) {
264 + return _addListener(this, type, listener, true);
265 + };
266 +
267 +function _onceWrap(target, type, listener) {
268 + var fired = false;
269 + function g() {
270 + target.removeListener(type, g);
271 + if (!fired) {
272 + fired = true;
273 + listener.apply(target, arguments);
274 + }
275 + }
276 + g.listener = listener;
277 + return g;
278 +}
279 +
280 +EventEmitter.prototype.once = function once(type, listener) {
281 + if (typeof listener !== 'function')
282 + throw new TypeError('"listener" argument must be a function');
283 + this.on(type, _onceWrap(this, type, listener));
284 + return this;
285 +};
286 +
287 +EventEmitter.prototype.prependOnceListener =
288 + function prependOnceListener(type, listener) {
289 + if (typeof listener !== 'function')
290 + throw new TypeError('"listener" argument must be a function');
291 + this.prependListener(type, _onceWrap(this, type, listener));
292 + return this;
293 + };
294 +
295 +// emits a 'removeListener' event iff the listener was removed
296 +EventEmitter.prototype.removeListener =
297 + function removeListener(type, listener) {
298 + var list, events, position, i, originalListener;
299 +
300 + if (typeof listener !== 'function')
301 + throw new TypeError('"listener" argument must be a function');
302 +
303 + events = this._events;
304 + if (!events)
305 + return this;
306 +
307 + list = events[type];
308 + if (!list)
309 + return this;
310 +
311 + if (list === listener || (list.listener && list.listener === listener)) {
312 + if (--this._eventsCount === 0)
313 + this._events = new EventHandlers();
314 + else {
315 + delete events[type];
316 + if (events.removeListener)
317 + this.emit('removeListener', type, list.listener || listener);
318 + }
319 + } else if (typeof list !== 'function') {
320 + position = -1;
321 +
322 + for (i = list.length; i-- > 0;) {
323 + if (list[i] === listener ||
324 + (list[i].listener && list[i].listener === listener)) {
325 + originalListener = list[i].listener;
326 + position = i;
327 + break;
328 + }
329 + }
330 +
331 + if (position < 0)
332 + return this;
333 +
334 + if (list.length === 1) {
335 + list[0] = undefined;
336 + if (--this._eventsCount === 0) {
337 + this._events = new EventHandlers();
338 + return this;
339 + } else {
340 + delete events[type];
341 + }
342 + } else {
343 + spliceOne(list, position);
344 + }
345 +
346 + if (events.removeListener)
347 + this.emit('removeListener', type, originalListener || listener);
348 + }
349 +
350 + return this;
351 + };
352 +
353 +EventEmitter.prototype.removeAllListeners =
354 + function removeAllListeners(type) {
355 + var listeners, events;
356 +
357 + events = this._events;
358 + if (!events)
359 + return this;
360 +
361 + // not listening for removeListener, no need to emit
362 + if (!events.removeListener) {
363 + if (arguments.length === 0) {
364 + this._events = new EventHandlers();
365 + this._eventsCount = 0;
366 + } else if (events[type]) {
367 + if (--this._eventsCount === 0)
368 + this._events = new EventHandlers();
369 + else
370 + delete events[type];
371 + }
372 + return this;
373 + }
374 +
375 + // emit removeListener for all listeners on all events
376 + if (arguments.length === 0) {
377 + var keys = Object.keys(events);
378 + for (var i = 0, key; i < keys.length; ++i) {
379 + key = keys[i];
380 + if (key === 'removeListener') continue;
381 + this.removeAllListeners(key);
382 + }
383 + this.removeAllListeners('removeListener');
384 + this._events = new EventHandlers();
385 + this._eventsCount = 0;
386 + return this;
387 + }
388 +
389 + listeners = events[type];
390 +
391 + if (typeof listeners === 'function') {
392 + this.removeListener(type, listeners);
393 + } else if (listeners) {
394 + // LIFO order
395 + do {
396 + this.removeListener(type, listeners[listeners.length - 1]);
397 + } while (listeners[0]);
398 + }
399 +
400 + return this;
401 + };
402 +
403 +EventEmitter.prototype.listeners = function listeners(type) {
404 + var evlistener;
405 + var ret;
406 + var events = this._events;
407 +
408 + if (!events)
409 + ret = [];
410 + else {
411 + evlistener = events[type];
412 + if (!evlistener)
413 + ret = [];
414 + else if (typeof evlistener === 'function')
415 + ret = [evlistener.listener || evlistener];
416 + else
417 + ret = unwrapListeners(evlistener);
418 + }
419 +
420 + return ret;
421 +};
422 +
423 +EventEmitter.listenerCount = function(emitter, type) {
424 + if (typeof emitter.listenerCount === 'function') {
425 + return emitter.listenerCount(type);
426 + } else {
427 + return listenerCount.call(emitter, type);
428 + }
429 +};
430 +
431 +EventEmitter.prototype.listenerCount = listenerCount;
432 +function listenerCount(type) {
433 + var events = this._events;
434 +
435 + if (events) {
436 + var evlistener = events[type];
437 +
438 + if (typeof evlistener === 'function') {
439 + return 1;
440 + } else if (evlistener) {
441 + return evlistener.length;
442 + }
443 + }
444 +
445 + return 0;
446 +}
447 +
448 +EventEmitter.prototype.eventNames = function eventNames() {
449 + return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
450 +};
451 +
452 +// About 1.5x faster than the two-arg version of Array#splice().
453 +function spliceOne(list, index) {
454 + for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
455 + list[i] = list[k];
456 + list.pop();
457 +}
458 +
459 +function arrayClone(arr, i) {
460 + var copy = new Array(i);
461 + while (i--)
462 + copy[i] = arr[i];
463 + return copy;
464 +}
465 +
466 +function unwrapListeners(arr) {
467 + var ret = new Array(arr.length);
468 + for (var i = 0; i < ret.length; ++i) {
469 + ret[i] = arr[i].listener || arr[i];
470 + }
471 + return ret;
472 +}
7 473
8 function __extends(d, b) { 474 function __extends(d, b) {
9 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; 475 for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
...@@ -11,56 +477,45 @@ function __extends(d, b) { ...@@ -11,56 +477,45 @@ function __extends(d, b) {
11 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 477 d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12 } 478 }
13 479
14 -var ElectronFileHandler = (function () { 480 +var ElectronFileHandler = (function (_super) {
481 + __extends(ElectronFileHandler, _super);
15 function ElectronFileHandler(ipcRenderer) { 482 function ElectronFileHandler(ipcRenderer) {
483 + _super.call(this);
16 this.ipcRenderer = ipcRenderer; 484 this.ipcRenderer = ipcRenderer;
17 } 485 }
18 ElectronFileHandler.prototype.download = function (source, target) { 486 ElectronFileHandler.prototype.download = function (source, target) {
19 var _this = this; 487 var _this = this;
20 - return rxjs.Observable.create(function (subscriber) { 488 + this.ipcRenderer.once('bsync-download-complete', function () {
21 - _this.ipcRenderer.once('bsync-download-complete', function () { 489 + _this.ipcRenderer.removeAllListeners('bsync-download-progress');
22 - _this.ipcRenderer.removeAllListeners('bsync-download-progress'); 490 + _this.ipcRenderer.removeAllListeners('bsync-download-error');
23 - _this.ipcRenderer.removeAllListeners('bsync-download-error'); 491 + _this.emit('complete');
24 - subscriber.complete(); 492 + });
25 - }); 493 + this.ipcRenderer.on('bsync-download-progress', function (progress) {
26 - _this.ipcRenderer.on('bsync-download-progress', function (progress) { 494 + _this.emit('progress', progress);
27 - subscriber.next(progress); 495 + });
28 - }); 496 + this.ipcRenderer.once('bsync-download-error', function (error) {
29 - _this.ipcRenderer.once('bsync-download-error', function (error) { 497 + _this.ipcRenderer.removeAllListeners('bsync-download-progress');
30 - _this.ipcRenderer.removeAllListeners('bsync-download-progress'); 498 + _this.ipcRenderer.removeAllListeners('bsync-download-complete');
31 - _this.ipcRenderer.removeAllListeners('bsync-download-complete'); 499 + _this.emit('error', error);
32 - subscriber.error(error);
33 - });
34 - _this.ipcRenderer.send('bsync-download', {
35 - source: source,
36 - target: target
37 - });
38 }); 500 });
501 + this.ipcRenderer.send('bsync-download', {
502 + source: source,
503 + target: target
504 + });
505 + return this;
39 }; 506 };
40 - return ElectronFileHandler; 507 + ElectronFileHandler.prototype.cleanup = function (files) {
41 -}()); 508 + var _this = this;
42 - 509 + return new Promise(function (resolve, reject) {
43 -var CordovaDownloader = (function () { 510 + _this.ipcRenderer.once('bsync-cleanup-complete', function () {
44 - function CordovaDownloader() { 511 + _this.emit('cleanup-complete');
45 - } 512 + resolve();
46 - CordovaDownloader.prototype.download = function (source, target) { 513 + });
47 - return Rx.Observable.create(function (subscriber) { 514 + _this.ipcRenderer.send('bsync-cleanup', files);
48 - if (!window['FileTransfer']) {
49 - subscriber.error("Cordova FileTransfer object undefined");
50 - }
51 - var fileTransfer = new window['FileTransfer']();
52 - fileTransfer.onprogress = function (progress) {
53 - subscriber.next(progress.loaded / progress.total);
54 - };
55 - fileTransfer.download(source, target, function (entry) {
56 - subscriber.complete();
57 - }, function (error) {
58 - subscriber.error(error);
59 - }, true);
60 }); 515 });
61 }; 516 };
62 - return CordovaDownloader; 517 + return ElectronFileHandler;
63 -}()); 518 +}(EventEmitter));
64 519
65 var Util = (function () { 520 var Util = (function () {
66 function Util() { 521 function Util() {
...@@ -71,9 +526,120 @@ var Util = (function () { ...@@ -71,9 +526,120 @@ var Util = (function () {
71 } 526 }
72 return "bsync_" + Math.abs(r); 527 return "bsync_" + Math.abs(r);
73 }; 528 };
529 + /**
530 + * index >= 0, localFile is in files
531 + * index < 0, localFile is not in files
532 + */
533 + Util.getFileIndex = function (files, localFile) {
534 + for (var i = 0; i < files.length; i++) {
535 + if (localFile == files[i].target) {
536 + return i;
537 + }
538 + }
539 + return -1;
540 + };
541 + Util.getFilesForCleanup = function (files, localFiles) {
542 + var filesForCleanup = [];
543 + for (var _i = 0, localFiles_1 = localFiles; _i < localFiles_1.length; _i++) {
544 + var localFile = localFiles_1[_i];
545 + var index = -1;
546 + index = Util.getFileIndex(files, localFile);
547 + if (index < 0) {
548 + filesForCleanup.push(localFile);
549 + }
550 + else {
551 + // splice for performance improvement only
552 + files.splice(index, 1);
553 + }
554 + }
555 + return filesForCleanup;
556 + };
74 return Util; 557 return Util;
75 }()); 558 }());
76 559
560 +var CordovaFileHandler = (function (_super) {
561 + __extends(CordovaFileHandler, _super);
562 + function CordovaFileHandler() {
563 + _super.apply(this, arguments);
564 + }
565 + CordovaFileHandler.prototype.triggerFileTransfer = function (source, target) {
566 + var _this = this;
567 + var fileTransfer = new window['FileTransfer']();
568 + fileTransfer.onprogress = function (progress) {
569 + _this.emit('progress', progress.loaded / progress.total);
570 + };
571 + fileTransfer.download(source, target, function (entry) {
572 + _this.emit('complete', entry);
573 + }, function (error) {
574 + _this.emit('error', error);
575 + }, true);
576 + };
577 + CordovaFileHandler.prototype.download = function (source, target) {
578 + var _this = this;
579 + if (!window['FileTransfer']) {
580 + this.emit('error', 'Cordova FileTransfer object undefined');
581 + }
582 + window['resolveLocalFileSystemURL'](target, function (entry) {
583 + entry.getMetadata(function (metadata) {
584 + if (metadata.size > 0) {
585 + _this.emit('complete', entry);
586 + }
587 + else {
588 + // file empty trigger transfer
589 + _this.triggerFileTransfer(source, target);
590 + }
591 + }, function () {
592 + // cannot read metadata trigger transfer
593 + _this.triggerFileTransfer(source, target);
594 + });
595 + }, function () {
596 + // file not found, so download it
597 + _this.triggerFileTransfer(source, target);
598 + });
599 + return this;
600 + };
601 + CordovaFileHandler.prototype.cleanup = function (files, basePath) {
602 + var _this = this;
603 + var filesForCleanup = [];
604 + return new Promise(function (resolve, reject) {
605 + if (window['resolveLocalFileSystemURL']) {
606 + window['resolveLocalFileSystemURL'](basePath, function (entry) {
607 + var reader = entry.createReader();
608 + reader.readEntries(function (entries) {
609 + for (var _i = 0, entries_1 = entries; _i < entries_1.length; _i++) {
610 + var e = entries_1[_i];
611 + if (e && e.isFile) {
612 + if (Util.getFileIndex(files, e.name) < 0) {
613 + filesForCleanup.push(e);
614 + }
615 + }
616 + }
617 + var index = 0;
618 + var error = false;
619 + var cleanupError = function (error) {
620 + _this.emit('cleanup-error', error);
621 + reject();
622 + error = true;
623 + };
624 + var cleanupNext = function () {
625 + if (index < filesForCleanup.length && !error) {
626 + filesForCleanup[index].remove(cleanupNext, cleanupError);
627 + index += 1;
628 + }
629 + else if (!error) {
630 + _this.emit('cleanup-complete', filesForCleanup);
631 + resolve();
632 + }
633 + };
634 + cleanupNext();
635 + }, function (error) { _this.emit('cleanup-error', error); reject(); });
636 + });
637 + }
638 + });
639 + };
640 + return CordovaFileHandler;
641 +}(EventEmitter));
642 +
77 var FileReplicator = (function (_super) { 643 var FileReplicator = (function (_super) {
78 __extends(FileReplicator, _super); 644 __extends(FileReplicator, _super);
79 function FileReplicator() { 645 function FileReplicator() {
...@@ -81,11 +647,13 @@ var FileReplicator = (function (_super) { ...@@ -81,11 +647,13 @@ var FileReplicator = (function (_super) {
81 this._files = []; 647 this._files = [];
82 this._itemValidator = null; 648 this._itemValidator = null;
83 this._fileHandler = null; 649 this._fileHandler = null;
84 - this._retryTimeout = 0; 650 + this._retryTimeout = 100;
651 + this._retries = 10;
85 this._itemKey = "type"; 652 this._itemKey = "type";
86 this._itemValue = "asset"; 653 this._itemValue = "asset";
87 this._itemSourceAttribute = "source"; 654 this._itemSourceAttribute = "source";
88 this._itemTargetAttribute = "target"; 655 this._itemTargetAttribute = "target";
656 + this._targetDirectory = "";
89 } 657 }
90 Object.defineProperty(FileReplicator.prototype, "files", { 658 Object.defineProperty(FileReplicator.prototype, "files", {
91 get: function () { 659 get: function () {
...@@ -95,6 +663,9 @@ var FileReplicator = (function (_super) { ...@@ -95,6 +663,9 @@ var FileReplicator = (function (_super) {
95 configurable: true 663 configurable: true
96 }); 664 });
97 Object.defineProperty(FileReplicator.prototype, "fileHandler", { 665 Object.defineProperty(FileReplicator.prototype, "fileHandler", {
666 + get: function () {
667 + return this._fileHandler;
668 + },
98 set: function (handler) { 669 set: function (handler) {
99 this._fileHandler = handler; 670 this._fileHandler = handler;
100 }, 671 },
...@@ -155,26 +726,36 @@ var FileReplicator = (function (_super) { ...@@ -155,26 +726,36 @@ var FileReplicator = (function (_super) {
155 enumerable: true, 726 enumerable: true,
156 configurable: true 727 configurable: true
157 }); 728 });
158 - FileReplicator.prototype.init = function (files) { 729 + Object.defineProperty(FileReplicator.prototype, "targetDirectory", {
730 + get: function () {
731 + return this._targetDirectory;
732 + },
733 + set: function (targetDirectory) {
734 + this._targetDirectory = targetDirectory;
735 + },
736 + enumerable: true,
737 + configurable: true
738 + });
739 + FileReplicator.prototype.clear = function (files) {
159 if (files === void 0) { files = []; } 740 if (files === void 0) { files = []; }
160 this._files = files; 741 this._files = files;
161 }; 742 };
162 /** 743 /**
163 * change from pouchdb replicate 744 * change from pouchdb replicate
164 */ 745 */
165 - FileReplicator.prototype.pushChanges = function (change) { 746 + FileReplicator.prototype.pushChanges = function (docs) {
166 var items = []; 747 var items = [];
167 - if (change && change.docs && change.docs.length > 0) { 748 + if (docs && docs.length > 0) {
168 - for (var _i = 0, _a = change.docs; _i < _a.length; _i++) { 749 + for (var _i = 0, docs_1 = docs; _i < docs_1.length; _i++) {
169 - var item = _a[_i]; 750 + var item = docs_1[_i];
170 if (item[this._itemKey] && item[this._itemKey] === this._itemValue) { 751 if (item[this._itemKey] && item[this._itemKey] === this._itemValue) {
171 items.push(item); 752 items.push(item);
172 } 753 }
173 } 754 }
174 } 755 }
175 var files = this.prepareFiles(items); 756 var files = this.prepareFiles(items);
176 - for (var _b = 0, files_1 = files; _b < files_1.length; _b++) { 757 + for (var _a = 0, files_1 = files; _a < files_1.length; _a++) {
177 - var file = files_1[_b]; 758 + var file = files_1[_a];
178 this._files.push(file); 759 this._files.push(file);
179 } 760 }
180 }; 761 };
...@@ -186,15 +767,19 @@ var FileReplicator = (function (_super) { ...@@ -186,15 +767,19 @@ var FileReplicator = (function (_super) {
186 } 767 }
187 this.emit('start', { progress: 0, index: index, length: files.length }); 768 this.emit('start', { progress: 0, index: index, length: files.length });
188 fileHandler 769 fileHandler
189 - .download(files[index].source, files[index].target) 770 + .on('progress', function (progress) {
190 - .subscribe(function (progress) { 771 + _this.emit('file-progress', { progress: progress, index: index, length: files.length });
191 - _this.emit('progress', { progress: progress, index: index, length: files.length }); 772 + })
192 - }, function (error) { 773 + .once('error', function (error) {
193 - _this.emit('error', { progress: 0, index: index, length: files.length, error: error }); 774 + _this.emit('file-error', { progress: 0, index: index, length: files.length, error: error });
194 - }, function () { 775 + fileHandler.removeAllListeners();
195 - _this.emit('complete', { progress: 100, index: index, length: files.length }); 776 + })
777 + .once('complete', function () {
778 + _this.emit('file-complete', { progress: 100, index: index, length: files.length });
779 + fileHandler.removeAllListeners();
196 _this.downloadFiles(files, fileHandler, index + 1); 780 _this.downloadFiles(files, fileHandler, index + 1);
197 - }); 781 + })
782 + .download(files[index].source, this.targetDirectory + files[index].target);
198 }; 783 };
199 FileReplicator.prototype.prepareFiles = function (items) { 784 FileReplicator.prototype.prepareFiles = function (items) {
200 var output = []; 785 var output = [];
...@@ -213,41 +798,62 @@ var FileReplicator = (function (_super) { ...@@ -213,41 +798,62 @@ var FileReplicator = (function (_super) {
213 } 798 }
214 return output; 799 return output;
215 }; 800 };
216 - FileReplicator.prototype.start = function () { 801 + FileReplicator.prototype.start = function (retries) {
217 var _this = this; 802 var _this = this;
218 - this.on('complete', function (event) { 803 + if (retries === void 0) { retries = 10; }
804 + this._retries = retries;
805 + this.on('file-complete', function (event) {
219 if ((event.index + 1) >= event.length) { 806 if ((event.index + 1) >= event.length) {
220 _this.replicationFinalized(event.index); 807 _this.replicationFinalized(event.index);
221 } 808 }
222 }); 809 });
223 - this.on('error', function (event) { 810 + this.on('file-error', function (event) {
224 _this.replicationFinalized(event.index); 811 _this.replicationFinalized(event.index);
225 }); 812 });
226 - this.downloadFiles(this._files, this._fileHandler); 813 + if (this._fileHandler && this._files.length > 0) {
814 + this.downloadFiles(this._files, this._fileHandler);
815 + }
816 + else {
817 + this.emit('complete');
818 + }
819 + };
820 + FileReplicator.prototype.cleanup = function () {
821 + var _this = this;
822 + this.fileHandler
823 + .cleanup(this._files, this._targetDirectory)
824 + .then(function () {
825 + _this.emit('cleanup-complete');
826 + }).catch(function () {
827 + _this.emit('cleanup-error');
828 + });
227 }; 829 };
228 FileReplicator.prototype.replicationFinalized = function (lastIndex) { 830 FileReplicator.prototype.replicationFinalized = function (lastIndex) {
229 var _this = this; 831 var _this = this;
230 if (lastIndex + 1 >= this._files.length) { 832 if (lastIndex + 1 >= this._files.length) {
231 - this._files = []; 833 + this.emit('complete');
232 - this.emit('final');
233 } 834 }
234 - else if (this._retryTimeout > 0) { 835 + else if (this._retries > 0) {
235 this._files.splice(0, lastIndex); 836 this._files.splice(0, lastIndex);
236 setTimeout(function () { 837 setTimeout(function () {
838 + _this._retries = -1;
237 _this.downloadFiles(_this._files, _this._fileHandler); 839 _this.downloadFiles(_this._files, _this._fileHandler);
238 }, this._retryTimeout); 840 }, this._retryTimeout);
239 } 841 }
842 + else {
843 + this.emit('error');
844 + }
240 }; 845 };
241 return FileReplicator; 846 return FileReplicator;
242 -}(events.EventEmitter)); 847 +}(EventEmitter));
243 848
244 var CONFIG_ITEM_KEY = "itemKey"; 849 var CONFIG_ITEM_KEY = "itemKey";
245 var CONFIG_ITEM_VALUE = "itemValue"; 850 var CONFIG_ITEM_VALUE = "itemValue";
246 var CONFIG_ITEM_SOURCE_ATTRIBUTE = "itemSourceAttribute"; 851 var CONFIG_ITEM_SOURCE_ATTRIBUTE = "itemSourceAttribute";
247 var CONFIG_ITEM_TARGET_ATTRIBUTE = "itemTargetAttribute"; 852 var CONFIG_ITEM_TARGET_ATTRIBUTE = "itemTargetAttribute";
248 - 853 +var CONFIG_ITEM_VALIDATOR = "itemValidator";
249 var CONFIG_RETRY_TIMEOUT = "retryTimeout"; 854 var CONFIG_RETRY_TIMEOUT = "retryTimeout";
250 - 855 +var CONFIG_FILE_HANDLER = "fileHandler";
856 +var CONFIG_TARGET_DIRECTORY = "targetDirectory";
251 var Config = (function () { 857 var Config = (function () {
252 function Config() { 858 function Config() {
253 this.config = {}; 859 this.config = {};
...@@ -263,6 +869,7 @@ var Config = (function () { ...@@ -263,6 +869,7 @@ var Config = (function () {
263 }; 869 };
264 Config.prototype.setConfig = function (key, value) { 870 Config.prototype.setConfig = function (key, value) {
265 this.config[key] = value; 871 this.config[key] = value;
872 + return this;
266 }; 873 };
267 return Config; 874 return Config;
268 }()); 875 }());
...@@ -300,7 +907,7 @@ var ServiceLocator = (function () { ...@@ -300,7 +907,7 @@ var ServiceLocator = (function () {
300 return new ElectronFileHandler(window['require']('electron').ipcRenderer); 907 return new ElectronFileHandler(window['require']('electron').ipcRenderer);
301 } 908 }
302 if (environment === ENV_CORDOVA) { 909 if (environment === ENV_CORDOVA) {
303 - return new CordovaDownloader(); 910 + return new CordovaFileHandler();
304 } 911 }
305 return null; 912 return null;
306 }; 913 };
...@@ -308,21 +915,24 @@ var ServiceLocator = (function () { ...@@ -308,21 +915,24 @@ var ServiceLocator = (function () {
308 if (!ServiceLocator.fileReplicator) { 915 if (!ServiceLocator.fileReplicator) {
309 ServiceLocator.fileReplicator = new FileReplicator(); 916 ServiceLocator.fileReplicator = new FileReplicator();
310 ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler(); 917 ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler();
311 - if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) { 918 + }
312 - ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT); 919 + if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) {
313 - } 920 + ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT);
314 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_KEY)) { 921 + }
315 - ServiceLocator.fileReplicator.itemKey = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_KEY); 922 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_KEY)) {
316 - } 923 + ServiceLocator.fileReplicator.itemKey = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_KEY);
317 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_VALUE)) { 924 + }
318 - ServiceLocator.fileReplicator.itemValue = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_VALUE); 925 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_VALUE)) {
319 - } 926 + ServiceLocator.fileReplicator.itemValue = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_VALUE);
320 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE)) { 927 + }
321 - ServiceLocator.fileReplicator.itemSourceAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE); 928 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE)) {
322 - } 929 + ServiceLocator.fileReplicator.itemSourceAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE);
323 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) { 930 + }
324 - ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE); 931 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) {
325 - } 932 + ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE);
933 + }
934 + if (ServiceLocator.getConfig().hasConfig(CONFIG_TARGET_DIRECTORY)) {
935 + ServiceLocator.fileReplicator.targetDirectory = ServiceLocator.getConfig().getConfig(CONFIG_TARGET_DIRECTORY);
326 } 936 }
327 return ServiceLocator.fileReplicator; 937 return ServiceLocator.fileReplicator;
328 }; 938 };
...@@ -330,61 +940,21 @@ var ServiceLocator = (function () { ...@@ -330,61 +940,21 @@ var ServiceLocator = (function () {
330 return ServiceLocator; 940 return ServiceLocator;
331 }()); 941 }());
332 942
333 -function loadBsyncPlugin(PouchDB) {
334 - var pouchReplicate = PouchDB.replicate;
335 - PouchDB.plugin(function (PouchDB) {
336 - PouchDB.replicate = function () {
337 - var eventEmitter = new events.EventEmitter();
338 - var emitter = pouchReplicate.apply(this, arguments);
339 - var replicator = ServiceLocator.getFileReplicator();
340 - var db = arguments[1];
341 - replicator.once('final', function (event) {
342 - eventEmitter.emit('complete');
343 - eventEmitter.removeAllListeners();
344 - });
345 - replicator.on('error', function (event) {
346 - eventEmitter.emit('file-replicator-error', event);
347 - });
348 - replicator.on('complete', function (event) {
349 - eventEmitter.emit('file-replicator-complete', event);
350 - });
351 - replicator.on('progress', function (event) {
352 - eventEmitter.emit('file-replicator-progress', event);
353 - });
354 - emitter.once('change', function (info) {
355 - eventEmitter.emit('change', info);
356 - });
357 - emitter.once('complete', function (info) {
358 - db.query('index_type/type', {
359 - include_docs: true,
360 - key: replicator.itemValue
361 - }).then(function (res) {
362 - var docs = { docs: [] };
363 - for (var _i = 0, _a = res.rows; _i < _a.length; _i++) {
364 - var r = _a[_i];
365 - docs.docs.push(r.doc);
366 - }
367 - replicator.pushChanges(docs);
368 - replicator.start();
369 - }).catch(function (error) {
370 - eventEmitter.emit('error', error);
371 - });
372 - });
373 - emitter.once('error', function (error) {
374 - eventEmitter.emit('error', error);
375 - });
376 - return eventEmitter;
377 - };
378 - });
379 -}
380 -
381 -if (typeof window !== 'undefined' && window['PouchDB']) {
382 - loadBsyncPlugin(window['PouchDB']);
383 -}
384 -
385 -exports.loadBsyncPlugin = loadBsyncPlugin;
386 exports.ENV_ELECTRON = ENV_ELECTRON; 943 exports.ENV_ELECTRON = ENV_ELECTRON;
387 exports.ENV_CORDOVA = ENV_CORDOVA; 944 exports.ENV_CORDOVA = ENV_CORDOVA;
388 exports.ENV_UNKNOWN = ENV_UNKNOWN; 945 exports.ENV_UNKNOWN = ENV_UNKNOWN;
389 exports.ServiceLocator = ServiceLocator; 946 exports.ServiceLocator = ServiceLocator;
947 +exports.CONFIG_ITEM_KEY = CONFIG_ITEM_KEY;
948 +exports.CONFIG_ITEM_VALUE = CONFIG_ITEM_VALUE;
949 +exports.CONFIG_ITEM_SOURCE_ATTRIBUTE = CONFIG_ITEM_SOURCE_ATTRIBUTE;
950 +exports.CONFIG_ITEM_TARGET_ATTRIBUTE = CONFIG_ITEM_TARGET_ATTRIBUTE;
951 +exports.CONFIG_ITEM_VALIDATOR = CONFIG_ITEM_VALIDATOR;
952 +exports.CONFIG_RETRY_TIMEOUT = CONFIG_RETRY_TIMEOUT;
953 +exports.CONFIG_FILE_HANDLER = CONFIG_FILE_HANDLER;
954 +exports.CONFIG_TARGET_DIRECTORY = CONFIG_TARGET_DIRECTORY;
955 +exports.Config = Config;
956 +
957 +Object.defineProperty(exports, '__esModule', { value: true });
958 +
959 +})));
390 //# sourceMappingURL=browser-build.js.map 960 //# sourceMappingURL=browser-build.js.map
......
1 -{"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 ...\ No newline at end of file
1 +{"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 ...\ No newline at end of file
......
1 'use strict'; 1 'use strict';
2 2
3 -var rxjs_Observable = require('rxjs/Observable'); 3 +var events = require('events');
4 var http = require('http'); 4 var http = require('http');
5 var https = require('https'); 5 var https = require('https');
6 var fs = require('fs'); 6 var fs = require('fs');
7 7
8 -var NodeFileHandler = (function () { 8 +function __extends(d, b) {
9 + for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
10 + function __() { this.constructor = d; }
11 + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12 +}
13 +
14 +var Util = (function () {
15 + function Util() {
16 + }
17 + Util.getNameHash = function (path) {
18 + for (var r = 0, i = 0; i < path.length; i++) {
19 + r = (r << 5) - r + path.charCodeAt(i), r &= r;
20 + }
21 + return "bsync_" + Math.abs(r);
22 + };
23 + /**
24 + * index >= 0, localFile is in files
25 + * index < 0, localFile is not in files
26 + */
27 + Util.getFileIndex = function (files, localFile) {
28 + for (var i = 0; i < files.length; i++) {
29 + if (localFile == files[i].target) {
30 + return i;
31 + }
32 + }
33 + return -1;
34 + };
35 + Util.getFilesForCleanup = function (files, localFiles) {
36 + var filesForCleanup = [];
37 + for (var _i = 0, localFiles_1 = localFiles; _i < localFiles_1.length; _i++) {
38 + var localFile = localFiles_1[_i];
39 + var index = -1;
40 + index = Util.getFileIndex(files, localFile);
41 + if (index < 0) {
42 + filesForCleanup.push(localFile);
43 + }
44 + else {
45 + // splice for performance improvement only
46 + files.splice(index, 1);
47 + }
48 + }
49 + return filesForCleanup;
50 + };
51 + return Util;
52 +}());
53 +
54 +var NodeFileHandler = (function (_super) {
55 + __extends(NodeFileHandler, _super);
9 function NodeFileHandler() { 56 function NodeFileHandler() {
57 + _super.apply(this, arguments);
10 } 58 }
11 NodeFileHandler.prototype.selectProtocol = function (url) { 59 NodeFileHandler.prototype.selectProtocol = function (url) {
12 if (url.search(/^http:\/\//) === 0) { 60 if (url.search(/^http:\/\//) === 0) {
...@@ -20,18 +68,19 @@ var NodeFileHandler = (function () { ...@@ -20,18 +68,19 @@ var NodeFileHandler = (function () {
20 } 68 }
21 }; 69 };
22 NodeFileHandler.prototype.download = function (source, target) { 70 NodeFileHandler.prototype.download = function (source, target) {
71 + var _this = this;
23 var handler = this.selectProtocol(source); 72 var handler = this.selectProtocol(source);
24 - return rxjs_Observable.Observable.create(function (subscriber) { 73 + if (!handler) {
25 - if (!handler) { 74 + this.emit("error", "No handler for source: " + source);
26 - subscriber.error("No handler for source: " + source); 75 + return this;
27 - return; 76 + }
28 - } 77 + // file already exists and is not empty
29 - // file already exists and is not empty 78 + if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
30 - if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) { 79 + this.emit("complete");
31 - subscriber.complete(); 80 + return this;
32 - return; 81 + }
33 - } 82 + else {
34 - var file = fs.createWriteStream(target, { 'flags': 'a' }); 83 + var file_1 = fs.createWriteStream(target, { 'flags': 'a' });
35 handler.get(source, function (response) { 84 handler.get(source, function (response) {
36 var size = response.headers['content-length']; // in bytes 85 var size = response.headers['content-length']; // in bytes
37 var prog = 0; // already downloaded 86 var prog = 0; // already downloaded
...@@ -39,33 +88,53 @@ var NodeFileHandler = (function () { ...@@ -39,33 +88,53 @@ var NodeFileHandler = (function () {
39 var nextProg = (1 / progCounts); 88 var nextProg = (1 / progCounts);
40 response.on('data', function (chunk) { 89 response.on('data', function (chunk) {
41 prog += chunk.length; 90 prog += chunk.length;
42 - file.write(chunk, 'binary'); 91 + file_1.write(chunk, 'binary');
43 if ((prog / size) > nextProg) { 92 if ((prog / size) > nextProg) {
44 - subscriber.next(prog / size); 93 + _this.emit('progress', prog / size);
45 nextProg += (1 / progCounts); 94 nextProg += (1 / progCounts);
46 } 95 }
47 }); 96 });
48 - response.on('end', function () { 97 + response.once('end', function () {
49 - file.end(); 98 + file_1.end();
50 - subscriber.complete(); 99 + _this.emit('complete');
51 }); 100 });
52 }).on('error', function (error) { 101 }).on('error', function (error) {
53 fs.unlink(target); 102 fs.unlink(target);
54 - subscriber.error("Error while downloading: " + error); 103 + _this.emit("error", "Error while downloading: " + error);
55 }); 104 });
56 - }); 105 + return this;
106 + }
107 + };
108 + NodeFileHandler.prototype.cleanup = function (files, basePath) {
109 + try {
110 + var localFiles = fs.readdirSync(basePath);
111 + Util.getFilesForCleanup(files, localFiles)
112 + .forEach(function (file) {
113 + fs.unlinkSync(basePath + "/" + file);
114 + });
115 + }
116 + catch (e) {
117 + }
118 + return this;
57 }; 119 };
58 return NodeFileHandler; 120 return NodeFileHandler;
59 -}()); 121 +}(events.EventEmitter));
60 122
61 var Bsync = (function () { 123 var Bsync = (function () {
62 function Bsync() { 124 function Bsync() {
63 } 125 }
64 - Bsync.configIpcMain = function (ipcMain, downloadDir) { 126 + Bsync.configIpcMain = function (ipcMain, basePath) {
65 - var nodeFileHander = new NodeFileHandler();
66 ipcMain.on('bsync-download', function (event, args) { 127 ipcMain.on('bsync-download', function (event, args) {
67 - nodeFileHander.download(args.source, downloadDir + args.target) 128 + var nodeFileHander = new NodeFileHandler();
68 - .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'); }); 129 + nodeFileHander.download(args.source, basePath + "/" + args.target)
130 + .on('progress', function (progress) { event.sender.send('bsync-download-progress', progress); })
131 + .once('error', function (error) { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-error', error); })
132 + .once('complete', function () { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-complete'); });
133 + });
134 + ipcMain.on('bsync-cleanup', function (event, args) {
135 + var nodeFileHandler = new NodeFileHandler();
136 + nodeFileHandler.cleanup(args.files, basePath);
137 + event.sender.send('bsync-cleanup-complete');
69 }); 138 });
70 }; 139 };
71 return Bsync; 140 return Bsync;
......
1 -{"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 ...\ No newline at end of file
1 +{"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 ...\ No newline at end of file
......
1 +
2 +interface FileReplicator {
3 + start(retries?:number) : void;
4 + clear() : void;
5 + cleanup() : void;
6 + pushChanges(change: any) : void;
7 + on(event:string, handler:(...params: any[]) => void) : FileReplicator;
8 + once(event:string, handler:(...params: any[]) => void) : FileReplicator;
9 + removeAllListeners() : FileReplicator;
10 +}
11 +
12 +declare var bsyncClient: {
13 +
14 + CONFIG_TARGET_DIRECTORY : string ;
15 +
16 + ServiceLocator : {
17 +
18 + getConfig : () => {
19 + getConfig : (key:string) => any;
20 + setConfig : (key:string, value:any) => void;
21 + hasConfig : (key:string) => boolean;
22 + };
23 +
24 + getFileReplicator : () => FileReplicator;
25 +
26 + }
27 +};
28 +
29 +declare module "bsync-client" {
30 + export = bsyncClient;
31 +}
...\ No newline at end of file ...\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
3 "version": "1.0.0", 3 "version": "1.0.0",
4 "description": "", 4 "description": "",
5 "main": "dist/browser-build.js", 5 "main": "dist/browser-build.js",
6 + "typings": "index.d.ts",
6 "scripts": { 7 "scripts": {
7 "build": "npm run build:node && npm run build:browser", 8 "build": "npm run build:node && npm run build:browser",
8 "build:node": "rollup -c ./config/rollup.config.node.js", 9 "build:node": "rollup -c ./config/rollup.config.node.js",
...@@ -16,9 +17,6 @@ ...@@ -16,9 +17,6 @@
16 }, 17 },
17 "author": "", 18 "author": "",
18 "license": "ISC", 19 "license": "ISC",
19 - "dependencies": {
20 - "rxjs": "^5.0.2"
21 - },
22 "devDependencies": { 20 "devDependencies": {
23 "@types/jasmine": "^2.5.40", 21 "@types/jasmine": "^2.5.40",
24 "cordova": "^6.4.0", 22 "cordova": "^6.4.0",
......
1 #!/bin/bash 1 #!/bin/bash
2 2
3 curl -X DELETE http://admin:admin@127.0.0.1:5984/pouch_test_db 3 curl -X DELETE http://admin:admin@127.0.0.1:5984/pouch_test_db
4 -rm -R ./.tmp
...\ No newline at end of file ...\ No newline at end of file
4 +rm -rf ./.tmp
5 +rm -rf ./.tmp-files
...\ No newline at end of file ...\ No newline at end of file
......
1 #!/bin/bash 1 #!/bin/bash
2 - 2 +rm -rf ./.tmp
3 +rm -rf ./.tmp-files
3 curl -X DELETE http://admin:admin@127.0.0.1:5984/pouch_test_db 4 curl -X DELETE http://admin:admin@127.0.0.1:5984/pouch_test_db
4 curl -X PUT http://admin:admin@127.0.0.1:5984/pouch_test_db 5 curl -X PUT http://admin:admin@127.0.0.1:5984/pouch_test_db
......
...@@ -7,15 +7,14 @@ echo "cordova $COMMAND $PLATFORM" ...@@ -7,15 +7,14 @@ echo "cordova $COMMAND $PLATFORM"
7 7
8 rollup --config ./config/rollup.config.cordova-test.js 8 rollup --config ./config/rollup.config.cordova-test.js
9 cp ./spec/cordova-plugin-test/plugin.xml .tmp/plugin.xml 9 cp ./spec/cordova-plugin-test/plugin.xml .tmp/plugin.xml
10 -cp ./node_modules/rxjs/bundles/Rx.min.js .tmp/Rx.min.js
11 10
12 cd .. 11 cd ..
13 -rm -r ./bsync-client-test-app 12 +rm -rf ./bsync-client-test-app
14 ./bsync-client/node_modules/.bin/cordova create bsync-client-test-app 13 ./bsync-client/node_modules/.bin/cordova create bsync-client-test-app
15 cd ./bsync-client-test-app 14 cd ./bsync-client-test-app
16 15
17 ../bsync-client/node_modules/.bin/cordova platform add $PLATFORM 16 ../bsync-client/node_modules/.bin/cordova platform add $PLATFORM
18 -../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client 17 +# ../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client
19 ../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client/.tmp 18 ../bsync-client/node_modules/.bin/cordova plugin add ../bsync-client/.tmp
20 ../bsync-client/node_modules/.bin/cordova plugin add cordova-plugin-test-framework 19 ../bsync-client/node_modules/.bin/cordova plugin add cordova-plugin-test-framework
21 20
...@@ -27,4 +26,4 @@ else ...@@ -27,4 +26,4 @@ else
27 cordova emulate $PLATFORM 26 cordova emulate $PLATFORM
28 fi 27 fi
29 28
30 -rm -R ../bsync-client/.tmp
...\ No newline at end of file ...\ No newline at end of file
29 +rm -rf ../bsync-client/.tmp
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -5,8 +5,6 @@ import {TestFileHandler} from './file-handler/test-file-handler'; ...@@ -5,8 +5,6 @@ import {TestFileHandler} from './file-handler/test-file-handler';
5 5
6 ServiceLocator.addFileHandler(ENV_UNKNOWN, new TestFileHandler()); 6 ServiceLocator.addFileHandler(ENV_UNKNOWN, new TestFileHandler());
7 7
8 -import '../src/browser-main';
9 -
10 declare var emit:any; 8 declare var emit:any;
11 9
12 const dbUrl = 'http://admin:admin@localhost:5984/pouch_test_db'; 10 const dbUrl = 'http://admin:admin@localhost:5984/pouch_test_db';
...@@ -49,32 +47,71 @@ describe("Integration tests with couchdb", () => { ...@@ -49,32 +47,71 @@ describe("Integration tests with couchdb", () => {
49 47
50 it("Should successfully download several files", (done) => { 48 it("Should successfully download several files", (done) => {
51 TestFileHandler.setErrorRate(0); 49 TestFileHandler.setErrorRate(0);
52 - ServiceLocator.getFileReplicator().init(); 50 + let replicator = ServiceLocator.getFileReplicator();
53 let index = 0; 51 let index = 0;
54 52
55 - localDb.replicate.from(dbUrl) 53 + replicator.clear();
56 - .on('file-replicator-complete', event => { 54 +
55 + replicator
56 + .on('file-complete', () => {
57 index++; 57 index++;
58 }) 58 })
59 - .on('complete', () => { 59 + .once('complete', () => {
60 expect(index).toEqual(3); 60 expect(index).toEqual(3);
61 - done(); 61 + done();
62 + });
63 +
64 + localDb.replicate.from(dbUrl)
65 + .once('complete', () => {
66 +
67 + localDb.query('index_type/type',{
68 + include_docs : true,
69 + key : replicator.itemValue
70 + }).then((res) => {
71 + let docs = [];
72 + for (let r of res.rows) {
73 + docs.push(r.doc);
74 + }
75 +
76 + replicator.pushChanges(docs);
77 + replicator.start();
78 + });
62 }); 79 });
63 }); 80 });
64 81
65 it("Should trigger errors, but successfully download with retries", (done) => { 82 it("Should trigger errors, but successfully download with retries", (done) => {
66 TestFileHandler.setErrorRate(0.8); 83 TestFileHandler.setErrorRate(0.8);
67 - ServiceLocator.getFileReplicator().init(); 84 + let replicator = ServiceLocator.getFileReplicator();
68 let errors = 0; 85 let errors = 0;
69 86
70 - localDb.replicate.from(dbUrl) 87 + replicator.clear();
71 - .on('file-replicator-error', event => { 88 +
89 + replicator
90 + .on('file-error', () => {
72 errors++; 91 errors++;
73 }) 92 })
74 - .on('complete', () => { 93 + .once('complete', () => {
75 expect(errors).toBeGreaterThanOrEqual(1); 94 expect(errors).toBeGreaterThanOrEqual(1);
76 - done(); 95 + done();
96 + });
97 +
98 + localDb.replicate.from(dbUrl)
99 + .once('complete', () => {
100 +
101 + localDb.query('index_type/type',{
102 + include_docs : true,
103 + key : replicator.itemValue
104 + }).then((res) => {
105 + let docs = [];
106 + for (let r of res.rows) {
107 + docs.push(r.doc);
108 + }
109 +
110 + replicator.pushChanges(docs);
111 + replicator.start();
112 + });
77 }); 113 });
114 +
78 }); 115 });
79 116
80 }); 117 });
......
...@@ -5,14 +5,11 @@ ...@@ -5,14 +5,11 @@
5 version="1.0.0" 5 version="1.0.0"
6 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 6 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
7 7
8 - <name>bsync cordova test</name> 8 + <name>bsync test in cordova environment</name>
9 <license>Apache 2.0 License</license> 9 <license>Apache 2.0 License</license>
10 -
11 - <js-module src="Rx.min.js" name="Rx">
12 - <clobbers target="Rx" />
13 - </js-module>
14 -
15 <js-module src="cordova-test-build.js" name="tests"> 10 <js-module src="cordova-test-build.js" name="tests">
16 </js-module> 11 </js-module>
17 12
13 + <dependency id="cordova-plugin-file-transfer" url="https://github.com/apache/cordova-plugin-file-transfer" commit="master" />
14 +
18 </plugin> 15 </plugin>
...\ No newline at end of file ...\ No newline at end of file
......
1 -import { CordovaDownloader } from '../src/file-handler/cordova-file-handler'; 1 +import { CordovaFileHandler } from '../src/file-handler/cordova-file-handler';
2 2
3 declare var cordova; 3 declare var cordova;
4 4
5 exports.defineAutoTests = function() { 5 exports.defineAutoTests = function() {
6 6
7 + let createFilesHelper = (filenames:Array<string>, successCallback, errorCallback) => {
8 + let index = 0;
9 +
10 + let create = () => {
11 + if (index < filenames.length) {
12 + console.log("try creating file: ", filenames[index]);
13 + createFileHelper(filenames[index], create, errorCallback);
14 + index += 1;
15 + } else {
16 + successCallback();
17 + }
18 + };
19 + create();
20 + };
21 +
22 + let createFileHelper = (filename, successCallback, errorCallback) => {
23 + window['requestFileSystem'](window['LocalFileSystem'].TEMPORARY, 0, (fs) => {
24 + fs.root.getFile(filename, { create: true, exclusive: false },(fileEntry) => {
25 + fileEntry.createWriter((fileWriter) => {
26 + fileWriter.onwriteend = function() {
27 + console.log("file created", filename);
28 + successCallback();
29 + };
30 + fileWriter.onerror = function (e) {
31 + console.error("file error", e);
32 + errorCallback(e);
33 + };
34 + fileWriter.write(new Blob(['some arbitrary file data'], { type: 'text/plain' }));
35 + });
36 + }, errorCallback);
37 + }, errorCallback);
38 + };
39 +
40 + jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000;
41 +
7 describe("Cordova downloader", () => { 42 describe("Cordova downloader", () => {
8 43
9 - let downloader = new CordovaDownloader(); 44 + let handler = new CordovaFileHandler();
10 45
11 it("should download sample image from https source and store with new name", (done) => { 46 it("should download sample image from https source and store with new name", (done) => {
12 47
13 - let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg"; 48 + let source = "https://upload.wikimedia.org/wikipedia/commons/f/ff/Pizigani_1367_Chart_10MB.jpg";
14 - let target = cordova.file.dataDirectory + "full-moon.jpg"; 49 + // let target = cordova.file.dataDirectory + "full-moon.jpg";
50 + let target = "cdvfile://localhost/temporary/full-moon.jpg";
15 let lastProgress = 0; 51 let lastProgress = 0;
16 52
17 - downloader.download(source, target) 53 + handler.download(source, target)
18 - .subscribe( 54 + .on('progress', (progress: number) => {
19 - (progress: number) => { 55 + expect(progress).toBeGreaterThan(lastProgress);
20 - expect(progress).toBeGreaterThan(lastProgress); 56 + lastProgress = progress;
21 - lastProgress = progress; 57 + }).once('error', (error:any) => {
22 - } , 58 + fail();
23 - (error:any) => { 59 + }).once('complete', () => {
24 - fail(); 60 + expect(lastProgress).toEqual(1);
25 - } , 61 +
26 - () => { 62 + window['resolveLocalFileSystemURL'](target, (entry:any) => {
27 - expect(lastProgress).toEqual(1); 63 + expect(entry.isFile).toBeTruthy();
28 - 64 + expect(entry.name).toEqual("full-moon.jpg");
29 - window['resolveLocalFileSystemURL'](target, (entry:any) => { 65 + done();
30 - expect(entry.isFile).toBeTruthy(); 66 + });
31 - expect(entry.name).toEqual("full-moon.jpg"); 67 + });
32 - done(); 68 + });
33 - }); 69 +
34 - } 70 + it('should cleanup successfully', (done) => {
35 - ); 71 + createFilesHelper(['file-1', 'file-2', 'file-3'], () => {
72 + console.log("files are created, now start with cleanup");
73 +
74 + handler.once('cleanup-complete', (files) => {
75 + console.log(files);
76 + expect(files.length).toBeGreaterThan(1);
77 + done();
78 + });
79 +
80 + handler.once('cleanup-error', (files) => {
81 + fail('cleanup error');
82 + });
36 83
84 + handler.cleanup([
85 + { source: '', target: 'file-1' } ,
86 + { source: '', target: 'file-2' }
87 + ], 'cdvfile://localhost/temporary/');
88 + }, (error) => {
89 + console.error(error);
90 + fail('error while creating files');
91 + });
37 }); 92 });
38 93
39 }); 94 });
......
1 -import { Observable, Subscriber } from 'rxjs'; 1 +import { EventEmitter } from 'events';
2 import { FileHandler } from '../../src/api/file-handler'; 2 import { FileHandler } from '../../src/api/file-handler';
3 3
4 -export class TestFileHandler implements FileHandler { 4 +export class TestFileHandler extends EventEmitter implements FileHandler {
5 5
6 protected static errorRate:number = 0; 6 protected static errorRate:number = 0;
7 7
...@@ -9,27 +9,30 @@ export class TestFileHandler implements FileHandler { ...@@ -9,27 +9,30 @@ export class TestFileHandler implements FileHandler {
9 TestFileHandler.errorRate = rate; 9 TestFileHandler.errorRate = rate;
10 } 10 }
11 11
12 - download(source:string, target:string) : Observable<number> { 12 + cleanup() { return this; }
13 - return Observable.create((subscriber:Subscriber<number>) => {
14 - let random = Math.random();
15 - let error:boolean = random < TestFileHandler.errorRate;
16 - let counter = 1;
17 13
18 - if (error) { 14 + download(source:string, target:string) {
19 - subscriber.error("random error triggered"); 15 + let random = Math.random();
20 - return; 16 + let error:boolean = random < TestFileHandler.errorRate;
21 - } 17 + let counter = 1;
22 18
19 + if (error) {
20 + setTimeout(() => {
21 + this.emit("error", "random error triggered");
22 + },200);
23 + } else {
23 let interval = setInterval(() => { 24 let interval = setInterval(() => {
24 if (counter < 4) { 25 if (counter < 4) {
25 - subscriber.next(counter * 25); 26 + this.emit('progress', counter * 25);
26 } else { 27 } else {
27 - subscriber.complete(); 28 + this.emit('complete');
28 clearInterval(interval); 29 clearInterval(interval);
29 } 30 }
30 31
31 ++counter; 32 ++counter;
32 }, 10); 33 }, 10);
33 - }); 34 + }
35 +
36 + return this;
34 } 37 }
35 } 38 }
...\ No newline at end of file ...\ No newline at end of file
......
1 export * from './test/file-handler/node-file-handler'; 1 export * from './test/file-handler/node-file-handler';
2 -export * from './test/file-replicator';
...\ No newline at end of file ...\ No newline at end of file
2 +export * from './test/file-replicator';
3 +export * from './test/util';
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -7,6 +7,10 @@ describe("Node Downloader", () => { ...@@ -7,6 +7,10 @@ describe("Node Downloader", () => {
7 7
8 let nodeFileHandler = new NodeFileHandler(); 8 let nodeFileHandler = new NodeFileHandler();
9 9
10 + beforeEach(() => {
11 + nodeFileHandler.removeAllListeners();
12 + });
13 +
10 it("should retrieve right handler", () => { 14 it("should retrieve right handler", () => {
11 15
12 let httpHandler = nodeFileHandler.selectProtocol("http://someurl.com/image.jpg"); 16 let httpHandler = nodeFileHandler.selectProtocol("http://someurl.com/image.jpg");
...@@ -23,27 +27,26 @@ describe("Node Downloader", () => { ...@@ -23,27 +27,26 @@ describe("Node Downloader", () => {
23 it("should download sample image from https source and store with new name", (done) => { 27 it("should download sample image from https source and store with new name", (done) => {
24 28
25 let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg"; 29 let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg";
26 - let target = ".tmp/full-moon.jpg"; 30 + let target = "./.tmp/full-moon-" + (new Date()).getTime() + ".jpg";
27 let lastProgress = 0; 31 let lastProgress = 0;
28 32
29 - nodeFileHandler.download(source, target) 33 + nodeFileHandler
30 - .subscribe( 34 + .on('progress', (progress: number) => {
31 - (progress: number) => { 35 + expect(progress).toBeGreaterThan(lastProgress);
32 - expect(progress).toBeGreaterThan(lastProgress); 36 + lastProgress = progress;
33 - lastProgress = progress; 37 + })
34 - } , 38 + .once('error', (error) => {})
35 - (error:any) => {} , 39 + .once('complete', () => {
36 - () => { 40 + expect(lastProgress).toEqual(1);
37 - expect(lastProgress).toEqual(1); 41 + expect(fs.existsSync(target)).toBeTruthy();
38 - expect(fs.existsSync(target)).toBeTruthy(); 42 + done();
39 - done(); 43 + })
40 - } 44 + .download(source, target);
41 - );
42 }); 45 });
43 46
44 it('should not download if file with same name exists and bytesize > 0', (done) => { 47 it('should not download if file with same name exists and bytesize > 0', (done) => {
45 let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg"; 48 let source = "https://upload.wikimedia.org/wikipedia/commons/thumb/e/e1/FullMoon2010.jpg/800px-FullMoon2010.jpg";
46 - let target = ".tmp/full-moon-sensless.jpg"; 49 + let target = "./.tmp/full-moon-sensless.jpg";
47 let lastProgress = 0; 50 let lastProgress = 0;
48 51
49 let file = fs.createWriteStream(target, {'flags': 'a'}); 52 let file = fs.createWriteStream(target, {'flags': 'a'});
...@@ -51,18 +54,32 @@ describe("Node Downloader", () => { ...@@ -51,18 +54,32 @@ describe("Node Downloader", () => {
51 54
52 file.write(new Buffer(dummyData)); 55 file.write(new Buffer(dummyData));
53 file.end(() => { 56 file.end(() => {
54 - 57 + nodeFileHandler
55 - nodeFileHandler.download(source, target) 58 + .on('progress', () => { fail("progress should not be called"); })
56 - .subscribe( 59 + .once('error', () => {})
57 - () => { fail("progress should not be called"); } , 60 + .once('complete', () => {
58 - () => {} ,
59 - () => {
60 expect(fs.existsSync(target)).toBeTruthy(); 61 expect(fs.existsSync(target)).toBeTruthy();
61 done(); 62 done();
62 - } 63 + })
63 - ); 64 + .download(source, target);
64 -
65 }); 65 });
66 }); 66 });
67 67
68 + it('should correctly cleanup files', () => {
69 + let basePath = "./.tmp-files";
70 + fs.mkdirSync(basePath);
71 + fs.writeFileSync(basePath + "/file1", "some data for file 1");
72 + fs.writeFileSync(basePath + "/file2", "some data for file 2");
73 + fs.writeFileSync(basePath + "/file3", "some data for file 3");
74 + fs.writeFileSync(basePath + "/file4", "some data for file 4");
75 +
76 + nodeFileHandler.cleanup([
77 + { source : '' , target : 'file1' },
78 + { source : '' , target : 'file2' }], basePath);
79 +
80 + let files = fs.readdirSync(basePath);
81 +
82 + expect(files.length).toEqual(2);
83 + });
84 +
68 }); 85 });
...\ No newline at end of file ...\ No newline at end of file
......
1 import { FileReplicator } from '../../src/file-replicator'; 1 import { FileReplicator } from '../../src/file-replicator';
2 2
3 -
4 describe("File Replicator", () => { 3 describe("File Replicator", () => {
5 4
6 let fileReplicator = new FileReplicator(); 5 let fileReplicator = new FileReplicator();
7 6
8 - let change = { 7 + let change = [
9 - docs : [ 8 + { language: 'de', type : "asset", source : "http://someplace.com/icon.jpg" , target : "icon.jpg" } ,
10 - { language: 'de', type : "asset", source : "http://someplace.com/icon.jpg" , target : "icon.jpg" } , 9 + { language: 'de', type : "asset", source : "http://sampleuri.com/image.png" } ,
11 - { language: 'de', type : "asset", source : "http://sampleuri.com/image.png" } , 10 + { language: 'en', type : "asset", source : "https://secureasset.com/asset.mp3" , target : "music.mp3" }
12 - { language: 'en', type : "asset", source : "https://secureasset.com/asset.mp3" , target : "music.mp3" } 11 + ];
13 - ]
14 - };
15 12
16 beforeEach(() => { 13 beforeEach(() => {
17 - fileReplicator.init(); 14 + fileReplicator.clear();
18 }); 15 });
19 16
20 it("should contain several assets", () => { 17 it("should contain several assets", () => {
...@@ -23,7 +20,7 @@ describe("File Replicator", () => { ...@@ -23,7 +20,7 @@ describe("File Replicator", () => {
23 }); 20 });
24 21
25 it("should get correct asset names", () => { 22 it("should get correct asset names", () => {
26 - let files = fileReplicator.prepareFiles(change.docs); 23 + let files = fileReplicator.prepareFiles(change);
27 24
28 expect(files[0].target).toEqual("icon.jpg"); 25 expect(files[0].target).toEqual("icon.jpg");
29 expect(files[1].target).toEqual("bsync_707608502"); 26 expect(files[1].target).toEqual("bsync_707608502");
...@@ -38,7 +35,7 @@ describe("File Replicator", () => { ...@@ -38,7 +35,7 @@ describe("File Replicator", () => {
38 return false; 35 return false;
39 }; 36 };
40 37
41 - let files = fileReplicator.prepareFiles(change.docs); 38 + let files = fileReplicator.prepareFiles(change);
42 39
43 expect(files.length).toEqual(2); 40 expect(files.length).toEqual(2);
44 expect(files[0].target).toEqual("icon.jpg"); 41 expect(files[0].target).toEqual("icon.jpg");
......
1 +import { Util } from '../../src/util';
2 +
3 +describe('Util', () => {
4 +
5 + let files = [
6 + { source : '' , target : 'file-1'} ,
7 + { source : '' , target : 'file-2'} ,
8 + { source : '' , target : 'file-3'} ,
9 + ];
10 +
11 + it('should show files to remove', () => {
12 + let cleanupFiles = Util.getFilesForCleanup(files, ['file-1','file-4']);
13 + expect(cleanupFiles[0]).toEqual('file-4');
14 + });
15 +
16 +});
...\ No newline at end of file ...\ No newline at end of file
1 -import { Observable } from 'rxjs/Observable'; 1 +import { File } from './file';
2 2
3 export interface FileHandler { 3 export interface FileHandler {
4 4
...@@ -8,6 +8,17 @@ export interface FileHandler { ...@@ -8,6 +8,17 @@ export interface FileHandler {
8 * - if the download is in progress: trigger next (0-1 progress for percent of download) 8 * - if the download is in progress: trigger next (0-1 progress for percent of download)
9 * - if the download enters any error condition, trigger error and an already downloaded part of the file 9 * - if the download enters any error condition, trigger error and an already downloaded part of the file
10 */ 10 */
11 - download(source:string, target:string) : Observable<number>; 11 + download(source:string, target:string) : FileHandler;
12 +
13 + /**
14 + * Remove all files, which are not inside the files array from local storage
15 + */
16 + cleanup(files: Array<File>, basePath?: string);
17 +
18 + on(event:string, handler:(...params: any[]) => void) : FileHandler;
19 +
20 + once(event:string, handler:(...params: any[]) => void) : FileHandler;
21 +
22 + removeAllListeners() : FileHandler;
12 23
13 } 24 }
...\ No newline at end of file ...\ No newline at end of file
......
1 -import { EventEmitter } from 'events';
2 import { ServiceLocator } from './service-locator'; 1 import { ServiceLocator } from './service-locator';
3 2
4 export * from './service-locator'; 3 export * from './service-locator';
5 4
6 -export function loadBsyncPlugin (PouchDB) { 5 +export * from './config';
7 - let pouchReplicate = PouchDB.replicate;
8 -
9 - PouchDB.plugin((PouchDB) => {
10 - PouchDB.replicate = function() {
11 - let eventEmitter = new EventEmitter();
12 - let emitter = pouchReplicate.apply(this, arguments);
13 - let replicator = ServiceLocator.getFileReplicator();
14 - let db = arguments[1];
15 -
16 - replicator.once('final', event => {
17 - eventEmitter.emit('complete');
18 - eventEmitter.removeAllListeners();
19 - });
20 -
21 - replicator.on('error', event => {
22 - eventEmitter.emit('file-replicator-error', event);
23 - });
24 -
25 - replicator.on('complete', event => {
26 - eventEmitter.emit('file-replicator-complete', event);
27 - });
28 -
29 - replicator.on('progress', event => {
30 - eventEmitter.emit('file-replicator-progress', event);
31 - });
32 -
33 - emitter.once('change', info => {
34 - eventEmitter.emit('change', info);
35 - });
36 -
37 - emitter.once('complete', info => {
38 - db.query('index_type/type',{
39 - include_docs : true,
40 - key : replicator.itemValue
41 - }).then((res) => {
42 - let docs = { docs : [] };
43 - for (let r of res.rows) {
44 - docs.docs.push(r.doc);
45 - }
46 -
47 - replicator.pushChanges(docs);
48 - replicator.start();
49 - }).catch(error => {
50 - eventEmitter.emit('error', error);
51 - });
52 - });
53 -
54 - emitter.once('error', (error) => {
55 - eventEmitter.emit('error', error);
56 - });
57 -
58 - return eventEmitter;
59 - };
60 - });
61 -};
62 -
63 -if (typeof window !== 'undefined' && window['PouchDB']) {
64 - loadBsyncPlugin(window['PouchDB']);
65 -}
......
...@@ -5,24 +5,26 @@ export const CONFIG_ITEM_TARGET_ATTRIBUTE = "itemTargetAttribute"; ...@@ -5,24 +5,26 @@ export const CONFIG_ITEM_TARGET_ATTRIBUTE = "itemTargetAttribute";
5 export const CONFIG_ITEM_VALIDATOR = "itemValidator"; 5 export const CONFIG_ITEM_VALIDATOR = "itemValidator";
6 export const CONFIG_RETRY_TIMEOUT = "retryTimeout"; 6 export const CONFIG_RETRY_TIMEOUT = "retryTimeout";
7 export const CONFIG_FILE_HANDLER = "fileHandler"; 7 export const CONFIG_FILE_HANDLER = "fileHandler";
8 +export const CONFIG_TARGET_DIRECTORY = "targetDirectory";
8 9
9 export class Config { 10 export class Config {
10 11
11 protected config:any = {}; 12 protected config:any = {};
12 13
13 - hasConfig(key:string) { 14 + hasConfig(key:string) : boolean {
14 if (this.config[key]) { 15 if (this.config[key]) {
15 return true; 16 return true;
16 } 17 }
17 return false; 18 return false;
18 } 19 }
19 20
20 - getConfig(key:string) { 21 + getConfig(key:string) : any {
21 return this.config[key]; 22 return this.config[key];
22 } 23 }
23 24
24 - setConfig(key:string, value:any) { 25 + setConfig(key:string, value:any) : Config {
25 this.config[key] = value; 26 this.config[key] = value;
27 + return this;
26 } 28 }
27 29
28 } 30 }
...\ No newline at end of file ...\ No newline at end of file
......
1 +import { Util } from './../util';
2 +import { EventEmitter } from 'events';
1 import { FileHandler } from '../api/file-handler'; 3 import { FileHandler } from '../api/file-handler';
4 +import { File } from '../api/file';
2 5
3 -declare var Rx; 6 +export class CordovaFileHandler extends EventEmitter implements FileHandler {
4 7
5 -export class CordovaDownloader implements FileHandler { 8 + triggerFileTransfer(source:string, target:string) {
9 + let fileTransfer = new window['FileTransfer']();
6 10
7 - download(source:string, target:string) : Rx.Observable<number> { 11 + fileTransfer.onprogress = (progress:ProgressEvent) => {
8 - return Rx.Observable.create((subscriber:Rx.Subscriber<number>) => { 12 + this.emit('progress', progress.loaded / progress.total);
13 + };
9 14
10 - if (!window['FileTransfer']) { 15 + fileTransfer.download(
11 - subscriber.error("Cordova FileTransfer object undefined"); 16 + source ,
17 + target ,
18 + (entry:any) => {
19 + this.emit('complete', entry);
20 + } ,
21 + (error:any) => {
22 + this.emit('error', error);
23 + },
24 + true
25 + );
26 + }
27 +
28 + download(source:string, target:string) {
29 + if (!window['FileTransfer']) {
30 + this.emit('error','Cordova FileTransfer object undefined');
31 + }
32 +
33 + window['resolveLocalFileSystemURL'](target, (entry:any) => {
34 + entry.getMetadata((metadata) => {
35 + if (metadata.size > 0) {
36 + this.emit('complete', entry);
37 + } else {
38 + // file empty trigger transfer
39 + this.triggerFileTransfer(source,target);
40 + }
41 + }, () => {
42 + // cannot read metadata trigger transfer
43 + this.triggerFileTransfer(source,target);
44 + });
45 + }, () => {
46 + // file not found, so download it
47 + this.triggerFileTransfer(source,target);
48 + });
49 +
50 + return this;
51 + }
52 +
53 + cleanup(files:Array<File>, basePath:string) : Promise<void> {
54 + let filesForCleanup = [];
55 +
56 + return new Promise<void>((resolve, reject) => {
57 +
58 + if (window['resolveLocalFileSystemURL']) {
59 + window['resolveLocalFileSystemURL'](basePath, (entry) => {
60 + let reader = entry.createReader();
61 + reader.readEntries((entries) => {
62 +
63 + for (let e of entries) {
64 + if (e && e.isFile) {
65 + if (Util.getFileIndex(files, e.name) < 0) {
66 + filesForCleanup.push(e);
67 + }
68 + }
69 + }
70 +
71 + let index = 0;
72 + let error = false;
73 +
74 + let cleanupError = (error) => {
75 + this.emit('cleanup-error', error);
76 + reject();
77 + error = true;
78 + };
79 +
80 + let cleanupNext = () => {
81 + if (index < filesForCleanup.length && !error) {
82 + filesForCleanup[index].remove(cleanupNext, cleanupError);
83 + index += 1;
84 + } else if (!error) {
85 + this.emit('cleanup-complete', filesForCleanup);
86 + resolve();
87 + }
88 + };
89 +
90 + cleanupNext();
91 +
92 + }, (error) => { this.emit('cleanup-error', error); reject(); });
93 + });
12 } 94 }
13 95
14 - let fileTransfer = new window['FileTransfer'](); 96 + });
15 -
16 - fileTransfer.onprogress = (progress:ProgressEvent) => {
17 - subscriber.next(progress.loaded / progress.total);
18 - };
19 -
20 - fileTransfer.download(
21 - source ,
22 - target ,
23 - (entry:any) => {
24 - subscriber.complete();
25 - } ,
26 - (error:any) => {
27 - subscriber.error(error);
28 - },
29 - true
30 - );
31 -
32 - });
33 } 97 }
34 98
35 } 99 }
...\ No newline at end of file ...\ No newline at end of file
......
1 -import { Observable, Subscriber } from 'rxjs'; 1 +import { EventEmitter } from 'events';
2 import { FileHandler } from '../api/file-handler'; 2 import { FileHandler } from '../api/file-handler';
3 +import { File } from '../api/file';
3 4
4 -export class ElectronFileHandler implements FileHandler { 5 +export class ElectronFileHandler extends EventEmitter implements FileHandler {
5 6
6 constructor (private ipcRenderer:any) { 7 constructor (private ipcRenderer:any) {
8 + super();
7 } 9 }
8 10
9 - download(source:string, target:string) : Observable<number> { 11 + download(source:string, target:string) {
10 - return Observable.create((subscriber:Subscriber<number>) => { 12 + this.ipcRenderer.once('bsync-download-complete', () => {
13 + this.ipcRenderer.removeAllListeners('bsync-download-progress');
14 + this.ipcRenderer.removeAllListeners('bsync-download-error');
15 + this.emit('complete');
16 + });
11 17
12 - this.ipcRenderer.once('bsync-download-complete', () => { 18 + this.ipcRenderer.on('bsync-download-progress', (progress:number) => {
13 - this.ipcRenderer.removeAllListeners('bsync-download-progress'); 19 + this.emit('progress', progress);
14 - this.ipcRenderer.removeAllListeners('bsync-download-error'); 20 + });
15 - subscriber.complete();
16 - });
17 21
18 - this.ipcRenderer.on('bsync-download-progress', (progress:number) => { 22 + this.ipcRenderer.once('bsync-download-error', (error:any) => {
19 - subscriber.next(progress); 23 + this.ipcRenderer.removeAllListeners('bsync-download-progress');
20 - }); 24 + this.ipcRenderer.removeAllListeners('bsync-download-complete');
25 + this.emit('error', error);
26 + });
21 27
22 - this.ipcRenderer.once('bsync-download-error', (error:any) => { 28 + this.ipcRenderer.send('bsync-download', {
23 - this.ipcRenderer.removeAllListeners('bsync-download-progress'); 29 + source : source ,
24 - this.ipcRenderer.removeAllListeners('bsync-download-complete'); 30 + target : target
25 - subscriber.error(error); 31 + });
26 - }); 32 +
33 + return this;
34 + }
27 35
28 - this.ipcRenderer.send('bsync-download', { 36 + cleanup(files:Array<File>) : Promise<void> {
29 - source : source , 37 + return new Promise<void>((resolve, reject) => {
30 - target : target 38 +
39 + this.ipcRenderer.once('bsync-cleanup-complete', () => {
40 + this.emit('cleanup-complete');
41 + resolve();
31 }); 42 });
43 +
44 + this.ipcRenderer.send('bsync-cleanup', files);
45 +
32 }); 46 });
33 } 47 }
34 48
......
1 -import { Observable } from 'rxjs/Observable'; 1 +import { Util } from './../util';
2 -import { Subscriber } from 'rxjs/Subscriber'; 2 +import { EventEmitter } from 'events';
3 import { FileHandler } from '../api/file-handler'; 3 import { FileHandler } from '../api/file-handler';
4 +import { File } from '../api/file';
4 import * as http from 'http'; 5 import * as http from 'http';
5 import * as https from 'https'; 6 import * as https from 'https';
6 import * as fs from 'fs'; 7 import * as fs from 'fs';
7 8
8 -export class NodeFileHandler implements FileHandler { 9 +export class NodeFileHandler extends EventEmitter implements FileHandler {
9 10
10 selectProtocol(url:string) : any { 11 selectProtocol(url:string) : any {
11 if (url.search(/^http:\/\//) === 0) { 12 if (url.search(/^http:\/\//) === 0) {
...@@ -17,23 +18,20 @@ export class NodeFileHandler implements FileHandler { ...@@ -17,23 +18,20 @@ export class NodeFileHandler implements FileHandler {
17 } 18 }
18 } 19 }
19 20
20 - download(source:string, target:string) : Observable<number> { 21 + download(source:string, target:string) {
21 22
22 let handler = this.selectProtocol(source); 23 let handler = this.selectProtocol(source);
23 24
24 - return Observable.create((subscriber:Subscriber<number>) => { 25 + if (!handler) {
25 - 26 + this.emit("error","No handler for source: " + source);
26 - if (!handler) { 27 + return this;
27 - subscriber.error("No handler for source: " + source); 28 + }
28 - return;
29 - }
30 -
31 - // file already exists and is not empty
32 - if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
33 - subscriber.complete();
34 - return;
35 - }
36 29
30 + // file already exists and is not empty
31 + if (fs.existsSync(target) && (fs.statSync(target)['size'] > 0)) {
32 + this.emit("complete");
33 + return this;
34 + } else {
37 let file = fs.createWriteStream(target, {'flags': 'a'}); 35 let file = fs.createWriteStream(target, {'flags': 'a'});
38 36
39 handler.get(source, (response) => { 37 handler.get(source, (response) => {
...@@ -41,29 +39,42 @@ export class NodeFileHandler implements FileHandler { ...@@ -41,29 +39,42 @@ export class NodeFileHandler implements FileHandler {
41 let prog = 0; // already downloaded 39 let prog = 0; // already downloaded
42 let progCounts = 100; // how many progress events should be triggerd (1-100 %) 40 let progCounts = 100; // how many progress events should be triggerd (1-100 %)
43 let nextProg = (1/progCounts); 41 let nextProg = (1/progCounts);
44 - 42 +
45 response.on('data', (chunk) => { 43 response.on('data', (chunk) => {
46 prog += chunk.length; 44 prog += chunk.length;
47 file.write(chunk, 'binary'); 45 file.write(chunk, 'binary');
48 46
49 if ((prog / size) > nextProg) { 47 if ((prog / size) > nextProg) {
50 - subscriber.next(prog / size); 48 + this.emit('progress',prog / size);
51 nextProg += (1 / progCounts); 49 nextProg += (1 / progCounts);
52 } 50 }
53 }); 51 });
54 52
55 - response.on('end', () => { 53 + response.once('end', () => {
56 file.end(); 54 file.end();
57 - subscriber.complete(); 55 + this.emit('complete');
58 - }); 56 + });
59 - 57 +
60 }).on('error', (error) => { 58 }).on('error', (error) => {
61 fs.unlink(target); 59 fs.unlink(target);
62 - subscriber.error("Error while downloading: " + error); 60 + this.emit("error", "Error while downloading: " + error);
63 }); 61 });
64 62
65 - }); 63 + return this;
64 + }
65 + }
66 66
67 + cleanup(files:Array<File>, basePath?:string) {
68 + try {
69 + let localFiles = fs.readdirSync(basePath);
70 + Util.getFilesForCleanup(files, localFiles)
71 + .forEach((file) => {
72 + fs.unlinkSync(basePath + "/" + file);
73 + });
74 + } catch (e) {
75 + }
76 +
77 + return this;
67 } 78 }
68 79
69 } 80 }
...\ No newline at end of file ...\ No newline at end of file
......
1 -import {FileHandler} from './api/file-handler'; 1 +import { FileHandler } from './api/file-handler';
2 -import {File} from './api/file'; 2 +import { File } from './api/file';
3 -import {Util} from './util'; 3 +import { Util } from './util';
4 -import {EventEmitter} from 'events'; 4 +import { EventEmitter } from 'events';
5 5
6 export class FileReplicator extends EventEmitter { 6 export class FileReplicator extends EventEmitter {
7 7
...@@ -9,46 +9,52 @@ export class FileReplicator extends EventEmitter { ...@@ -9,46 +9,52 @@ export class FileReplicator extends EventEmitter {
9 super(); 9 super();
10 } 10 }
11 11
12 - protected _files:Array<File> = []; 12 + protected _files: Array<File> = [];
13 13
14 - protected _itemValidator: (item:any) => boolean = null; 14 + protected _itemValidator: (item: any) => boolean = null;
15 - protected _fileHandler:FileHandler = null; 15 + protected _fileHandler: FileHandler = null;
16 - protected _retryTimeout:number = 0; 16 + protected _retryTimeout: number = 100;
17 - 17 + protected _retries: number = 10;
18 - protected _itemKey = "type"; 18 +
19 + protected _itemKey = "type";
19 protected _itemValue = "asset"; 20 protected _itemValue = "asset";
20 protected _itemSourceAttribute = "source"; 21 protected _itemSourceAttribute = "source";
21 protected _itemTargetAttribute = "target"; 22 protected _itemTargetAttribute = "target";
23 + protected _targetDirectory = "";
22 24
23 get files(): Array<File> { 25 get files(): Array<File> {
24 return this._files; 26 return this._files;
25 } 27 }
26 28
27 - set fileHandler (handler:FileHandler) { 29 + set fileHandler(handler: FileHandler) {
28 this._fileHandler = handler; 30 this._fileHandler = handler;
29 } 31 }
30 32
31 - set retryTimeout (timeout:number) { 33 + get fileHandler() : FileHandler {
34 + return this._fileHandler;
35 + }
36 +
37 + set retryTimeout(timeout: number) {
32 this._retryTimeout = timeout; 38 this._retryTimeout = timeout;
33 } 39 }
34 40
35 - set itemValidator(validator:(item:any) => boolean) { 41 + set itemValidator(validator: (item: any) => boolean) {
36 this._itemValidator = validator; 42 this._itemValidator = validator;
37 } 43 }
38 44
39 - set itemKey(key:string) { 45 + set itemKey(key: string) {
40 this._itemKey = key; 46 this._itemKey = key;
41 } 47 }
42 48
43 - set itemValue(value:string) { 49 + set itemValue(value: string) {
44 this._itemValue = value; 50 this._itemValue = value;
45 } 51 }
46 52
47 - set itemSourceAttribute(sourceAttribute:string) { 53 + set itemSourceAttribute(sourceAttribute: string) {
48 this._itemSourceAttribute = sourceAttribute; 54 this._itemSourceAttribute = sourceAttribute;
49 } 55 }
50 56
51 - set itemTargetAttribute(targetAttribute:string) { 57 + set itemTargetAttribute(targetAttribute: string) {
52 this._itemTargetAttribute = targetAttribute; 58 this._itemTargetAttribute = targetAttribute;
53 } 59 }
54 60
...@@ -68,24 +74,32 @@ export class FileReplicator extends EventEmitter { ...@@ -68,24 +74,32 @@ export class FileReplicator extends EventEmitter {
68 return this._itemTargetAttribute; 74 return this._itemTargetAttribute;
69 } 75 }
70 76
71 - init(files: Array<File> = []) { 77 + set targetDirectory(targetDirectory: string) {
78 + this._targetDirectory = targetDirectory;
79 + }
80 +
81 + get targetDirectory() {
82 + return this._targetDirectory;
83 + }
84 +
85 + clear(files: Array<File> = []) {
72 this._files = files; 86 this._files = files;
73 } 87 }
74 88
75 /** 89 /**
76 * change from pouchdb replicate 90 * change from pouchdb replicate
77 */ 91 */
78 - pushChanges(change:any) { 92 + pushChanges(docs: Array<any>) {
79 - let items:Array<any> = []; 93 + let items: Array<any> = [];
80 94
81 - if (change && change.docs && change.docs.length > 0) { 95 + if (docs && docs.length > 0) {
82 - for (let item of change.docs) { 96 + for (let item of docs) {
83 if (item[this._itemKey] && item[this._itemKey] === this._itemValue) { 97 if (item[this._itemKey] && item[this._itemKey] === this._itemValue) {
84 items.push(item); 98 items.push(item);
85 } 99 }
86 } 100 }
87 } 101 }
88 - 102 +
89 let files = this.prepareFiles(items); 103 let files = this.prepareFiles(items);
90 104
91 for (let file of files) { 105 for (let file of files) {
...@@ -93,35 +107,35 @@ export class FileReplicator extends EventEmitter { ...@@ -93,35 +107,35 @@ export class FileReplicator extends EventEmitter {
93 } 107 }
94 } 108 }
95 109
96 - downloadFiles(files:Array<File>, fileHandler:FileHandler, index:number = 0) { 110 + downloadFiles(files: Array<File>, fileHandler: FileHandler, index: number = 0) {
97 if (index >= files.length) { 111 if (index >= files.length) {
98 return; 112 return;
99 } 113 }
100 114
101 - this.emit('start', { progress: 0, index : index, length : files.length }); 115 + this.emit('start', { progress: 0, index: index, length: files.length });
102 - 116 +
103 fileHandler 117 fileHandler
104 - .download(files[index].source, files[index].target) 118 + .on('progress', (progress) => {
105 - .subscribe( 119 + this.emit('file-progress', { progress: progress, index: index, length: files.length })
106 - progress => { 120 + })
107 - this.emit('progress', { progress : progress, index : index, length : files.length }) 121 + .once('error', error => {
108 - } , 122 + this.emit('file-error', { progress: 0, index: index, length: files.length, error: error });
109 - error => { 123 + fileHandler.removeAllListeners();
110 - this.emit('error', { progress : 0, index : index, length : files.length, error: error }); 124 + })
111 - } , 125 + .once('complete', () => {
112 - () => { 126 + this.emit('file-complete', { progress: 100, index: index, length: files.length });
113 - this.emit('complete', { progress : 100 , index : index, length : files.length }); 127 + fileHandler.removeAllListeners();
114 - this.downloadFiles(files, fileHandler, index+1); 128 + this.downloadFiles(files, fileHandler, index + 1);
115 - } 129 + })
116 - ); 130 + .download(files[index].source, this.targetDirectory + files[index].target);
117 - } 131 + }
118 - 132 +
119 - prepareFiles(items: Array<any>) : Array<File> { 133 + prepareFiles(items: Array<any>): Array<File> {
120 let output = []; 134 let output = [];
121 135
122 for (let item of items) { 136 for (let item of items) {
123 if (item[this._itemSourceAttribute] && (!this._itemValidator || this._itemValidator(item))) { 137 if (item[this._itemSourceAttribute] && (!this._itemValidator || this._itemValidator(item))) {
124 - let file = { source : item[this._itemSourceAttribute] , target : '' }; 138 + let file = { source: item[this._itemSourceAttribute], target: '' };
125 139
126 if (item[this._itemTargetAttribute]) { 140 if (item[this._itemTargetAttribute]) {
127 file.target = item[this._itemTargetAttribute]; 141 file.target = item[this._itemTargetAttribute];
...@@ -136,30 +150,48 @@ export class FileReplicator extends EventEmitter { ...@@ -136,30 +150,48 @@ export class FileReplicator extends EventEmitter {
136 return output; 150 return output;
137 } 151 }
138 152
139 - start() { 153 + start(retries:number = 10) {
140 - this.on('complete', (event:any) => { 154 + this._retries = retries;
155 +
156 + this.on('file-complete', (event: any) => {
141 if ((event.index + 1) >= event.length) { 157 if ((event.index + 1) >= event.length) {
142 this.replicationFinalized(event.index); 158 this.replicationFinalized(event.index);
143 } 159 }
144 }); 160 });
145 161
146 - this.on('error', (event:any) => { 162 + this.on('file-error', (event: any) => {
147 this.replicationFinalized(event.index); 163 this.replicationFinalized(event.index);
148 - }); 164 + });
149 165
150 - this.downloadFiles(this._files, this._fileHandler); 166 + if (this._fileHandler && this._files.length > 0) {
167 + this.downloadFiles(this._files, this._fileHandler);
168 + } else {
169 + this.emit('complete');
170 + }
171 + }
172 +
173 + cleanup() {
174 + this.fileHandler
175 + .cleanup(this._files, this._targetDirectory)
176 + .then(() => {
177 + this.emit('cleanup-complete');
178 + }).catch(() => {
179 + this.emit('cleanup-error');
180 + });
151 } 181 }
152 182
153 - replicationFinalized(lastIndex:number) { 183 + replicationFinalized(lastIndex: number) {
154 - if (lastIndex+1 >= this._files.length) { // all finished 184 + if (lastIndex + 1 >= this._files.length) { // all finished
155 - this._files = []; 185 + this.emit('complete');
156 - this.emit('final'); 186 + } else if (this._retries > 0) { // restart after last success
157 - } else if (this._retryTimeout > 0) { // restart after last success 187 + this._files.splice(0, lastIndex);
158 - this._files.splice(0,lastIndex); 188 + setTimeout(() => {
159 - setTimeout(() => { 189 + this._retries =- 1;
160 this.downloadFiles(this._files, this._fileHandler); 190 this.downloadFiles(this._files, this._fileHandler);
161 }, this._retryTimeout); 191 }, this._retryTimeout);
162 - } 192 + } else {
193 + this.emit('error');
194 + }
163 } 195 }
164 196
165 } 197 }
...\ No newline at end of file ...\ No newline at end of file
......
...@@ -2,17 +2,22 @@ import { NodeFileHandler } from './file-handler/node-file-handler'; ...@@ -2,17 +2,22 @@ import { NodeFileHandler } from './file-handler/node-file-handler';
2 2
3 export default class Bsync { 3 export default class Bsync {
4 4
5 - static configIpcMain(ipcMain: any, downloadDir:string) { 5 + static configIpcMain(ipcMain: any, basePath: string) {
6 - let nodeFileHander = new NodeFileHandler(); 6 +
7 -
8 ipcMain.on('bsync-download', (event, args) => { 7 ipcMain.on('bsync-download', (event, args) => {
9 - nodeFileHander.download(args.source, downloadDir + args.target) 8 + let nodeFileHander = new NodeFileHandler();
10 - .subscribe( 9 + nodeFileHander.download(args.source, basePath + "/" + args.target)
11 - (progress:number) => { event.sender.send('bsync-download-progress', progress); } , 10 + .on('progress', (progress:number) => { event.sender.send('bsync-download-progress', progress); })
12 - (error:any) => { event.sender.send('bsync-download-error', error); } , 11 + .once('error', (error) => { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-error', error); })
13 - () => { event.sender.send('bsync-download-complete'); } 12 + .once('complete', () => { nodeFileHander.removeAllListeners(); event.sender.send('bsync-download-complete'); });
14 - ); 13 + });
14 +
15 + ipcMain.on('bsync-cleanup', (event, args) => {
16 + let nodeFileHandler = new NodeFileHandler();
17 + nodeFileHandler.cleanup(args.files, basePath);
18 + event.sender.send('bsync-cleanup-complete');
15 }); 19 });
20 +
16 } 21 }
17 22
18 } 23 }
...\ No newline at end of file ...\ No newline at end of file
......
1 import {FileHandler} from './api/file-handler'; 1 import {FileHandler} from './api/file-handler';
2 import {ElectronFileHandler} from './file-handler/electron-file-handler'; 2 import {ElectronFileHandler} from './file-handler/electron-file-handler';
3 -import {CordovaDownloader} from './file-handler/cordova-file-handler'; 3 +import {CordovaFileHandler} from './file-handler/cordova-file-handler';
4 import {FileReplicator} from './file-replicator'; 4 import {FileReplicator} from './file-replicator';
5 import { 5 import {
6 Config, 6 Config,
...@@ -8,7 +8,8 @@ import { ...@@ -8,7 +8,8 @@ import {
8 CONFIG_ITEM_KEY, 8 CONFIG_ITEM_KEY,
9 CONFIG_ITEM_VALUE, 9 CONFIG_ITEM_VALUE,
10 CONFIG_ITEM_TARGET_ATTRIBUTE, 10 CONFIG_ITEM_TARGET_ATTRIBUTE,
11 - CONFIG_ITEM_SOURCE_ATTRIBUTE 11 + CONFIG_ITEM_SOURCE_ATTRIBUTE,
12 + CONFIG_TARGET_DIRECTORY
12 } from './config'; 13 } from './config';
13 14
14 export const ENV_ELECTRON = "electron"; 15 export const ENV_ELECTRON = "electron";
...@@ -56,7 +57,7 @@ export class ServiceLocator { ...@@ -56,7 +57,7 @@ export class ServiceLocator {
56 } 57 }
57 58
58 if (environment === ENV_CORDOVA) { 59 if (environment === ENV_CORDOVA) {
59 - return new CordovaDownloader(); 60 + return new CordovaFileHandler();
60 } 61 }
61 62
62 return null; 63 return null;
...@@ -64,28 +65,29 @@ export class ServiceLocator { ...@@ -64,28 +65,29 @@ export class ServiceLocator {
64 65
65 static getFileReplicator() : FileReplicator { 66 static getFileReplicator() : FileReplicator {
66 if (!ServiceLocator.fileReplicator) { 67 if (!ServiceLocator.fileReplicator) {
67 -
68 ServiceLocator.fileReplicator = new FileReplicator(); 68 ServiceLocator.fileReplicator = new FileReplicator();
69 -
70 ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler(); 69 ServiceLocator.fileReplicator.fileHandler = ServiceLocator.getFileHandler();
70 + }
71 71
72 - if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) { 72 + if (ServiceLocator.getConfig().hasConfig(CONFIG_RETRY_TIMEOUT)) {
73 - ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT); 73 + ServiceLocator.fileReplicator.retryTimeout = ServiceLocator.getConfig().getConfig(CONFIG_RETRY_TIMEOUT);
74 - } 74 + }
75 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_KEY)) { 75 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_KEY)) {
76 - ServiceLocator.fileReplicator.itemKey = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_KEY); 76 + ServiceLocator.fileReplicator.itemKey = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_KEY);
77 - } 77 + }
78 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_VALUE)) { 78 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_VALUE)) {
79 - ServiceLocator.fileReplicator.itemValue = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_VALUE); 79 + ServiceLocator.fileReplicator.itemValue = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_VALUE);
80 - } 80 + }
81 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE)) { 81 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE)) {
82 - ServiceLocator.fileReplicator.itemSourceAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE); 82 + ServiceLocator.fileReplicator.itemSourceAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_SOURCE_ATTRIBUTE);
83 - } 83 + }
84 - if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) { 84 + if (ServiceLocator.getConfig().hasConfig(CONFIG_ITEM_TARGET_ATTRIBUTE)) {
85 - ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE); 85 + ServiceLocator.fileReplicator.itemTargetAttribute = ServiceLocator.getConfig().getConfig(CONFIG_ITEM_TARGET_ATTRIBUTE);
86 - } 86 + }
87 - } 87 + if (ServiceLocator.getConfig().hasConfig(CONFIG_TARGET_DIRECTORY)) {
88 - 88 + ServiceLocator.fileReplicator.targetDirectory = ServiceLocator.getConfig().getConfig(CONFIG_TARGET_DIRECTORY);
89 + }
90 +
89 return ServiceLocator.fileReplicator; 91 return ServiceLocator.fileReplicator;
90 } 92 }
91 93
......
1 +import { File } from './api/file';
2 +
1 export class Util { 3 export class Util {
2 4
3 static getNameHash(path:string) { 5 static getNameHash(path:string) {
...@@ -7,4 +9,36 @@ export class Util { ...@@ -7,4 +9,36 @@ export class Util {
7 return "bsync_" + Math.abs(r); 9 return "bsync_" + Math.abs(r);
8 } 10 }
9 11
12 + /**
13 + * index >= 0, localFile is in files
14 + * index < 0, localFile is not in files
15 + */
16 + static getFileIndex(files:Array<File>, localFile:string) : number {
17 + for (let i = 0; i < files.length; i++) {
18 + if (localFile == files[i].target) {
19 + return i;
20 + }
21 + }
22 + return -1;
23 + }
24 +
25 + static getFilesForCleanup(files:Array<File>, localFiles:Array<string>) : Array<string> {
26 + let filesForCleanup = [];
27 +
28 + for (let localFile of localFiles) {
29 + let index = -1;
30 +
31 + index = Util.getFileIndex(files, localFile);
32 +
33 + if (index < 0) {
34 + filesForCleanup.push(localFile);
35 + } else {
36 + // splice for performance improvement only
37 + files.splice(index,1);
38 + }
39 + }
40 +
41 + return filesForCleanup;
42 + }
43 +
10 } 44 }
...\ No newline at end of file ...\ No newline at end of file
......