UNPKG

19.1 kBJavaScriptView Raw
1'use strict';
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6
7var _regenerator = require('babel-runtime/regenerator');
8
9var _regenerator2 = _interopRequireDefault(_regenerator);
10
11var _asyncToGenerator2 = require('babel-runtime/helpers/asyncToGenerator');
12
13var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
14
15var _typeof2 = require('babel-runtime/helpers/typeof');
16
17var _typeof3 = _interopRequireDefault(_typeof2);
18
19var _keys = require('babel-runtime/core-js/object/keys');
20
21var _keys2 = _interopRequireDefault(_keys);
22
23var _cache = require('./cache');
24
25var _cache2 = _interopRequireDefault(_cache);
26
27var _uuid = require('uuid');
28
29var _uuid2 = _interopRequireDefault(_uuid);
30
31var _lodash = require('lodash');
32
33var _lodash2 = _interopRequireDefault(_lodash);
34
35function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
36
37var urlLib = require('url');
38var pointer = require('json-pointer');
39var websocket = require('./websocket');
40var Promise = require('bluebird');
41var axios = require('axios');
42var oadaIdClient = require('@oada/oada-id-client');
43
44var connect = function connect(_ref) {
45 var _this3 = this;
46
47 // Ensure all resources down to the deepest resource are created before
48 // performing a PUT.
49 var put = function () {
50 var _ref13 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee3(_ref12) {
51 var url = _ref12.url,
52 path = _ref12.path,
53 data = _ref12.data,
54 type = _ref12.type,
55 headers = _ref12.headers,
56 tree = _ref12.tree;
57 var req, pieces, treePath;
58 return _regenerator2.default.wrap(function _callee3$(_context3) {
59 while (1) {
60 switch (_context3.prev = _context3.next) {
61 case 0:
62 req = {
63 method: 'put',
64 url: url || DOMAIN + path,
65 headers: _lodash2.default.merge({ 'Authorization': 'Bearer ' + TOKEN }, headers),
66 data: data
67 };
68
69 if (type) req.headers['Content-Type'] = type;
70
71 if (!tree) {
72 _context3.next = 5;
73 break;
74 }
75
76 _context3.next = 5;
77 return _ensureTree({
78 url: req.url,
79 tree: _lodash2.default.cloneDeep(tree),
80 data: data
81 });
82
83 case 5:
84 pieces = urlLib.parse(req.url).path.replace(/^\//, '').split('/');
85 treePath = _convertSetupTreePath(pieces, tree) + '/_type';
86
87 if (pointer.has(tree, treePath)) req.headers['Content-Type'] = pointer.get(tree, treePath);
88 return _context3.abrupt('return', REQUEST(req));
89
90 case 9:
91 case 'end':
92 return _context3.stop();
93 }
94 }
95 }, _callee3, this);
96 }));
97
98 return function put(_x3) {
99 return _ref13.apply(this, arguments);
100 };
101 }();
102
103 var resetCache = function () {
104 var _ref14 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee4(name, exp) {
105 return _regenerator2.default.wrap(function _callee4$(_context4) {
106 while (1) {
107 switch (_context4.prev = _context4.next) {
108 case 0:
109 if (CACHE) {
110 _context4.next = 2;
111 break;
112 }
113
114 return _context4.abrupt('return');
115
116 case 2:
117 _context4.next = 4;
118 return CACHE.resetCache();
119
120 case 4:
121 return _context4.abrupt('return', _configureCache({
122 name: NAME,
123 req: SOCKET.http || axios,
124 exp: exp || EXP
125 }));
126
127 case 5:
128 case 'end':
129 return _context4.stop();
130 }
131 }
132 }, _callee4, this);
133 }));
134
135 return function resetCache(_x4, _x5) {
136 return _ref14.apply(this, arguments);
137 };
138 }();
139
140 var domain = _ref.domain,
141 options = _ref.options,
142 cache = _ref.cache,
143 token = _ref.token,
144 noWebsocket = _ref.noWebsocket;
145
146 var CACHE = undefined;
147 var REQUEST = axios;
148 var SOCKET = undefined;
149 var TOKEN = undefined;
150 var DOMAIN = domain;
151 var NAME = urlLib.parse(domain).hostname.replace(/\./g, '_');
152 var EXP = cache ? cache.exp : undefined;
153
154 if (!DOMAIN) throw 'domain undefined';
155
156 function _replaceLinks(obj) {
157 var ret = Array.isArray(obj) ? [] : {};
158 if (!obj) return obj; // no defined objriptors for this level
159 return Promise.map((0, _keys2.default)(obj || {}), function (key) {
160 if (key === '*') {
161 // Don't put *s into oada. Ignore them
162 return;
163 }
164 var val = obj[key];
165 if ((typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) !== 'object' || !val) {
166 ret[key] = val; // keep it asntType: 'application/vnd.oada.harvest.1+json'
167 return;
168 }
169 if (val._type) {
170 // If it has a '_type' key, don't worry about it.
171 //It'll get created in future iterations of ensureTree
172 return;
173 }
174 if (val._id) {
175 // If it's an object, and has an '_id', make it a link from descriptor
176 ret[key] = { _id: obj[key]._id };
177 if (val._rev) ret[key]._rev = '0-0';
178 return;
179 }
180 // otherwise, recurse into the object looking for more links
181 return _replaceLinks(val).then(function (result) {
182 ret[key] = result;
183 return;
184 });
185 }).then(function () {
186 return ret;
187 });
188 }
189
190 function _makeResourceAndLink(_ref2) {
191 var path = _ref2.path,
192 data = _ref2.data;
193
194 var req = {
195 path: data._id ? '/' + data._id : '/resources/' + (0, _uuid2.default)(),
196 type: data._type,
197 data: data
198 };
199 var link = {
200 path: path,
201 type: data._type,
202 data: { _id: data._id || req.path.replace(/^\//, '') }
203 };
204 if (data._rev) link.data._rev = '0-0';
205 return put(link).then(function () {
206 return put(req);
207 });
208 }
209
210 function _watch(_ref3) {
211 var _this = this;
212
213 var headers = _ref3.headers,
214 path = _ref3.path,
215 func = _ref3.func,
216 payload = _ref3.payload;
217
218 if (SOCKET) {
219 return SOCKET.watch({
220 path: path,
221 headers: headers
222 }, function () {
223 var _ref4 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee(response) {
224 return _regenerator2.default.wrap(function _callee$(_context) {
225 while (1) {
226 switch (_context.prev = _context.next) {
227 case 0:
228 if (!payload) payload = {};
229 payload.response = response;
230 payload.request = {
231 url: DOMAIN + path,
232 headers: headers,
233 method: payload.response.change.type
234 };
235
236 if (!CACHE) {
237 _context.next = 6;
238 break;
239 }
240
241 _context.next = 6;
242 return CACHE.handleWatchChange(payload);
243
244 case 6:
245 return _context.abrupt('return', func(payload));
246
247 case 7:
248 case 'end':
249 return _context.stop();
250 }
251 }
252 }, _callee, this);
253 }));
254
255 function watchResponse(_x) {
256 return _ref4.apply(this, arguments);
257 }
258
259 return watchResponse;
260 }());
261 } else {
262 // Ping a normal GET every 5 seconds in the absense of a websocket
263 return setInterval(function () {
264 _this.get({ url: url }).then(function (result) {
265 func(payload);
266 });
267 }, 5000);
268 }
269 }
270
271 function get(_ref5) {
272 var _this2 = this;
273
274 var url = _ref5.url,
275 path = _ref5.path,
276 headers = _ref5.headers,
277 watch = _ref5.watch,
278 tree = _ref5.tree;
279
280 var req = {
281 method: 'get',
282 url: url || DOMAIN + path,
283 headers: _lodash2.default.merge({ 'Authorization': 'Bearer ' + TOKEN }, headers)
284 };
285
286 var prom = void 0;
287
288 if (tree) {
289 // Tree must be rooted at /bookmarks. Get the subtree for the given path.
290 var pieces = urlLib.parse(req.url).path.replace(/^\//, '').split('/');
291 var treePath = _convertSetupTreePath(pieces, tree);
292 if (!pointer.has(tree, treePath)) return get({ url: url });
293 tree = pointer.get(tree, treePath);
294 prom = _recursiveGet(req.url, tree, {}).then(function (res) {
295 return {
296 data: res,
297 status: 200
298 };
299 }).catch(function (err) {
300 return;
301 });
302 } else {
303 prom = REQUEST(req);
304 }
305
306 return prom.then(function () {
307 var _ref6 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee2(response) {
308 return _regenerator2.default.wrap(function _callee2$(_context2) {
309 while (1) {
310 switch (_context2.prev = _context2.next) {
311 case 0:
312 if (!watch) {
313 _context2.next = 6;
314 break;
315 }
316
317 path = path || urlLib.parse(url).path;
318 req.headers['x-oada-rev'] = response.data._rev;
319 console.log(path, response.data._rev);
320 _context2.next = 6;
321 return _watch({
322 headers: req.headers,
323 path: path,
324 func: watch.func,
325 payload: watch.payload
326 });
327
328 case 6:
329 return _context2.abrupt('return', response);
330
331 case 7:
332 case 'end':
333 return _context2.stop();
334 }
335 }
336 }, _callee2, _this2);
337 }));
338
339 return function (_x2) {
340 return _ref6.apply(this, arguments);
341 };
342 }());
343 }
344
345 function _recursiveGet(url, tree, returnData) {
346 return Promise.try(function () {
347 // Perform a GET if we have reached the next resource break.
348 if (tree._type) {
349 // its a resource
350 return get({
351 url: url
352 }).then(function (response) {
353 returnData = response.data;
354 return;
355 });
356 }
357 return tree;
358 }).then(function () {
359 // Walk down the data at this url and continue recursion.
360 return Promise.map((0, _keys2.default)(tree || {}), function (key) {
361 // If tree contains a *, this means we should get ALL content on the server
362 // at this level and continue recursion for each returned key.
363 if (key === '*') {
364 return Promise.map((0, _keys2.default)(returnData || {}), function (resKey) {
365 if (resKey.charAt(0) === '_') return;
366 return _recursiveGet(url + '/' + resKey, tree[key] || {}, returnData[resKey]).then(function (res) {
367 return returnData[resKey] = res;
368 });
369 });
370 } else if ((0, _typeof3.default)(tree[key]) === 'object') {
371 return _recursiveGet(url + '/' + key, tree[key] || {}, returnData[key]).then(function (res) {
372 return returnData[key] = res;
373 });
374 } else return returnData[key];
375 }).then(function () {
376 return returnData;
377 });
378 }).catch(function (err) {
379 if (err.response.status === 404) {
380 return;
381 }
382 throw err;
383 });
384 }
385
386 // Identify the cached resources vs those that need to be setup.
387 function _findDeepestResources(pieces, tree, cachedTree) {
388 var cached = 0;
389 var setup = void 0;
390 // Walk down the url in reverse order
391 return Promise.mapSeries(pieces, function (piece, i) {
392 var z = pieces.length - 1 - i; //use z to create paths in reverse order
393 var urlPath = '/' + pieces.slice(0, z + 1).join('/');
394 var treePath = _convertSetupTreePath(pieces.slice(0, z + 1), tree);
395 // Check that its in the cached tree then look for deepest _resource_.
396 // If successful, break from the loop by throwing
397 if (pointer.has(tree, treePath + '/_type')) {
398 setup = setup || z;
399 if (pointer.has(cachedTree, urlPath)) {
400 cached = _lodash2.default.clone(z);
401 throw new Error('cached');
402 }
403 return get({
404 path: urlPath
405 }).then(function (response) {
406 pointer.set(cachedTree, urlPath, {});
407 cached = _lodash2.default.clone(z);
408 throw new Error('cached');
409 }).catch(function (err) {
410 // pointer.set(cachedTree, urlPath, {})
411 if (/^cached/.test(err.message)) throw err;
412 return;
413 });
414 }
415 return;
416 }).catch(function (err) {
417 // Throwing with a number error only should occur on success.
418 if (/^cached/.test(err.message)) return { cached: cached, setup: setup };
419 }).then(function () {
420 return {
421 cached: cached,
422 setup: setup || 0
423 };
424 });
425 }
426
427 // Loop over the keys of the path and determine whether the object at that level
428 // contains a * key. The path must be updated along the way, replacing *s as
429 // necessary.
430 function _convertSetupTreePath(pathPieces, tree) {
431 var newPieces = _lodash2.default.clone(pathPieces);
432 newPieces = pathPieces.map(function (piece, i) {
433 if (pointer.has(tree, '/' + newPieces.slice(0, i).join('/') + '/*')) {
434 newPieces[i] = '*';
435 return '*';
436 } else {
437 return piece;
438 }
439 });
440 return '/' + newPieces.join('/');
441 }
442
443 function _ensureTree(_ref7) {
444 var url = _ref7.url,
445 tree = _ref7.tree,
446 data = _ref7.data;
447
448 //If /resources
449
450 //If /bookmarks
451 var path = urlLib.parse(url).path.replace(/^\//, '');
452 var pieces = path.replace(/\/$/, '').split('/');
453 if (data._id) {
454 var firstPath = _convertSetupTreePath(pieces, tree);
455 pointer.set(tree, firstPath + '/_id', data._id);
456 }
457 // if (pointer.has(tree, treePath)) pointer.set(tree, treePath, _.merge(pointer.get(tree, treePath),data))
458 var cachedTree = {};
459 // Find the deepest part of the path that exists. Once found, work back down.
460 return _findDeepestResources(pieces, tree, cachedTree).then(function (ret) {
461 // Create all the resources on the way down. ret.cached is an index. Slice
462 // takes the length to slice, so no need to subtract 1.
463 return Promise.mapSeries(pieces.slice(0, pieces.length - ret.cached), function (piece, j) {
464 var i = ret.cached + 1 + j; // ret.cached exists; add one to continue beyond.
465 var urlPath = '/' + pieces.slice(0, i + 1).join('/');
466 var treePath = _convertSetupTreePath(pieces.slice(0, i + 1), tree);
467 if (pointer.has(tree, treePath + '/_type') && i <= ret.setup) {
468 // its a resource
469 return _replaceLinks(pointer.get(tree, treePath)).then(function (content) {
470 return _makeResourceAndLink({
471 path: urlPath,
472 data: _lodash2.default.cloneDeep(content)
473 }).then(function (resp) {
474 pointer.set(cachedTree, urlPath, content);
475 return resp;
476 }).catch(function (err) {
477 return err;
478 });
479 });
480 } else return;
481 });
482 }).then(function (responses) {
483 return responses[responses.length - 1];
484 }).catch(function (err) {
485 return err;
486 });
487 }
488
489 function post(_ref8) {
490 var url = _ref8.url,
491 path = _ref8.path,
492 data = _ref8.data,
493 type = _ref8.type,
494 headers = _ref8.headers,
495 tree = _ref8.tree;
496
497 url = url || DOMAIN + path;
498 url = url[url.length - 1] === '/' ? url + (0, _uuid2.default)() : url + '/' + (0, _uuid2.default)();
499 return put({
500 url: url,
501 data: data,
502 type: type,
503 headers: headers,
504 tree: tree
505 });
506 }
507
508 function del(_ref9) {
509 var url = _ref9.url,
510 path = _ref9.path,
511 headers = _ref9.headers,
512 unwatch = _ref9.unwatch;
513
514 var req = {
515 method: 'delete',
516 url: url || DOMAIN + path,
517 headers: _lodash2.default.merge({ 'Authorization': 'Bearer ' + TOKEN }, headers)
518 };
519
520 if (unwatch) {
521 console.log('UNWATCHING');
522 path = path || urlLib.parse(url).path;
523 return SOCKET.unwatch({
524 path: path,
525 headers: req.headers
526 }).then(function () {
527 console.log('UNWATCHING DONE');
528 return;
529 });
530 }
531
532 return REQUEST(req);
533 }
534
535 function _configureCache(_ref10) {
536 var name = _ref10.name,
537 req = _ref10.req,
538 exp = _ref10.exp;
539
540 var res = (0, _cache2.default)({ name: name, req: req, exp: exp });
541 REQUEST = res.api;
542 CACHE = res;
543 return;
544 }
545
546 function _configureWs(_ref11) {
547 var domain = _ref11.domain;
548
549 return websocket(domain).then(function (socketApi) {
550 REQUEST = socketApi.http;
551 return SOCKET = socketApi;
552 });
553 }
554
555 function disconnect() {
556 if (CACHE) CACHE.db.destroy();
557 if (CACHE) CACHE.db.close();
558 if (SOCKET) SOCKET.close();
559 }
560
561 var urlObj = urlLib.parse(domain);
562 var prom = void 0;
563 if (token) {
564 prom = Promise.resolve({ access_token: token });
565 } else {
566 if (typeof window === 'undefined') {
567 prom = oadaIdClient.node(urlObj.host, options);
568 } else {
569 // the library itself detects a browser environment and delivers .browser
570 var gat = Promise.promisify(oadaIdClient.getAccessToken);
571 prom = gat(urlObj.host, options);
572 }
573 }
574 return prom.then(function () {
575 var _ref15 = (0, _asyncToGenerator3.default)( /*#__PURE__*/_regenerator2.default.mark(function _callee5(result) {
576 var wsProm;
577 return _regenerator2.default.wrap(function _callee5$(_context5) {
578 while (1) {
579 switch (_context5.prev = _context5.next) {
580 case 0:
581 TOKEN = result.access_token;
582 wsProm = void 0;
583
584 if (!noWebsocket) {
585 wsProm = websocket(domain).then(function (socketApi) {
586 REQUEST = socketApi.http;
587 return SOCKET = socketApi;
588 });
589 } else wsProm = Promise.resolve();
590 return _context5.abrupt('return', wsProm.then(function () {
591 var cacheProm = void 0;
592 if (cache === false) return;
593 return _configureCache({
594 name: NAME || (0, _uuid2.default)(),
595 req: REQUEST,
596 exp: EXP
597 });
598 }));
599
600 case 4:
601 case 'end':
602 return _context5.stop();
603 }
604 }
605 }, _callee5, _this3);
606 }));
607
608 return function (_x6) {
609 return _ref15.apply(this, arguments);
610 };
611 }()).then(function (f) {
612 return {
613 token: TOKEN,
614 // cache: CACHE,
615 //socket: SOCKET,
616 get: get,
617 put: put,
618 post: post,
619 delete: del,
620 resetCache: resetCache,
621 disconnect: disconnect
622 };
623 });
624};
625
626exports.default = {
627 connect: connect
628};
\No newline at end of file