UNPKG

leveros

Version:

The Lever OS Node client library

223 lines (189 loc) 18.8 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.GRPCPool = undefined; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _leverosCommon = require('leveros-common'); var common = _interopRequireWildcard(_leverosCommon); var _grpc = require('grpc'); var _grpc2 = _interopRequireDefault(_grpc); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _sortedMap = require('collections/sorted-map'); var _sortedMap2 = _interopRequireDefault(_sortedMap); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } var GRPCPool = exports.GRPCPool = function () { function GRPCPool() { _classCallCheck(this, GRPCPool); var expiryMs = 5 * 60 * 1000; // 5 minutes in ms. this._conns = new Cache(expiryMs, this._newConn.bind(this), this._destroyConn.bind(this)); } _createClass(GRPCPool, [{ key: 'dial', value: function dial(target, callback) { this._conns.get(target, callback); } }, { key: 'keepAlive', value: function keepAlive(target) { this._conns.keepAlive(target); } }, { key: '_newConn', value: function _newConn(target, callback) { callback(null, new common.leverRPCProto.core.LeverRPC(target, _grpc2.default.credentials.createInsecure())); } }, { key: '_destroyConn', value: function _destroyConn(conn) { conn.$channel.close(); } }]); return GRPCPool; }(); var CacheEntry = function () { function CacheEntry() { _classCallCheck(this, CacheEntry); this.element = null; this.error = new Error("Not yet constructed"); this.lastUsed = null; this.keepAlive(); } _createClass(CacheEntry, [{ key: 'keepAlive', value: function keepAlive() { this.lastUsed = Date.now(); } }]); return CacheEntry; }(); var Cache = function () { function Cache(expiryMs, constr, destr) { _classCallCheck(this, Cache); this._expiryMs = expiryMs; this._constr = constr; this._destr = destr; this._data = {}; // key -> CacheEntry this._lastUsedMap = new _sortedMap2.default(); // lastUsed (ms) -> array of keys } _createClass(Cache, [{ key: 'get', value: function get(key, callback) { var _this = this; if (this._data.hasOwnProperty(key)) { this.keepAlive(key); var _entry = this._data[key]; setImmediate(callback.bind(null, _entry.error, _entry.element)); return; } var entry = new CacheEntry(); sortedMapInsert(this._lastUsedMap, entry.lastUsed, key); this._data[key] = entry; this._maybeScheduleExpire(entry.lastUsed); this._constr(key, function (error, element) { entry.error = error; entry.element = element; if (error) { // Remove from cache if construction failed. delete _this._data[key]; sortedMapRemove(_this._lastUsedMap, entry.lastUsed, key); } callback(error, element); }); } }, { key: '_destroyEntry', value: function _destroyEntry(entry) { if (entry.element !== null) { try { this._destr(entry.element); } catch (ex) { // Do nothing. } entry.element = null; entry.error = new Error("Was destructed"); } } }, { key: 'keepAlive', value: function keepAlive(key) { if (!this._data.hasOwnProperty(key)) { return false; } var entry = this._data[key]; sortedMapRemove(this._lastUsedMap, entry.lastUsed, key); entry.keepAlive(); sortedMapInsert(this._lastUsedMap, entry.lastUsed, key); this._maybeScheduleExpire(entry.lastUsed); return true; } }, { key: '_maybeScheduleExpire', value: function _maybeScheduleExpire(lastUsed) { if (this._lastUsedMap.store.min()[0] !== lastUsed) { // Already scheduled. return; } var value = this._lastUsedMap.get(lastUsed, []); if (value.length > 1) { // Already scheduled. return; } this._doExpire(); } }, { key: '_doExpire', value: function _doExpire() { var _this2 = this; while (this._lastUsedMap.length !== 0) { var lastUsed = this._lastUsedMap.store.min()[0]; var expiryTime = lastUsed + this._expiryMs; if (expiryTime <= Date.now()) { // Entry expired. var value = this._lastUsedMap.get(lastUsed, []); _lodash2.default.forEach(value, function (key) { var entry = _this2._data[key]; delete _this2._data[key]; _this2._destroyEntry(entry); }); this._lastUsedMap.delete(lastUsed); } else { // Not yet time. Schedule next. var untilExpiry = expiryTime - Date.now(); setTimeout(this._doExpire.bind(this), untilExpiry); return; } } } }]); return Cache; }(); function sortedMapInsert(map, key, target) { if (!map.has(key)) { map.set(key, [target]); return; } var value = map.get(key); value.push(target); map.set(key, value); } function sortedMapRemove(map, key, target) { if (!map.has(key)) { return; } var value = map.get(key); var foundIndex = _lodash2.default.indexOf(value, target); if (foundIndex === -1) { return; } value.splice(foundIndex, 1); if (value.length === 0) { map.delete(key); } else { map.set(key, value); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi9ncnBjcG9vbC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFDQTs7SUFBWSxNOztBQUNaOzs7O0FBQ0E7Ozs7QUFDQTs7Ozs7Ozs7OztJQUVhLFEsV0FBQSxRO0FBQ1Qsd0JBQWM7QUFBQTs7QUFDVixZQUFNLFdBQVcsSUFBSSxFQUFKLEdBQVMsSUFBMUIsQztBQUNBLGFBQUssTUFBTCxHQUFjLElBQUksS0FBSixDQUNWLFFBRFUsRUFDQSxLQUFLLFFBQUwsQ0FBYyxJQUFkLENBQW1CLElBQW5CLENBREEsRUFDMEIsS0FBSyxZQUFMLENBQWtCLElBQWxCLENBQXVCLElBQXZCLENBRDFCLENBQWQ7QUFFSDs7Ozs2QkFFSSxNLEVBQVEsUSxFQUFVO0FBQ25CLGlCQUFLLE1BQUwsQ0FBWSxHQUFaLENBQWdCLE1BQWhCLEVBQXdCLFFBQXhCO0FBQ0g7OztrQ0FFUyxNLEVBQVE7QUFDZCxpQkFBSyxNQUFMLENBQVksU0FBWixDQUFzQixNQUF0QjtBQUNIOzs7aUNBRVEsTSxFQUFRLFEsRUFBVTtBQUN2QixxQkFDSSxJQURKLEVBRUksSUFBSSxPQUFPLGFBQVAsQ0FBcUIsSUFBckIsQ0FBMEIsUUFBOUIsQ0FDSSxNQURKLEVBQ1ksZUFBSyxXQUFMLENBQWlCLGNBQWpCLEVBRFosQ0FGSjtBQUlIOzs7cUNBRVksSSxFQUFNO0FBQ2YsaUJBQUssUUFBTCxDQUFjLEtBQWQ7QUFDSDs7Ozs7O0lBR0MsVTtBQUNGLDBCQUFjO0FBQUE7O0FBQ1YsYUFBSyxPQUFMLEdBQWUsSUFBZjtBQUNBLGFBQUssS0FBTCxHQUFhLElBQUksS0FBSixDQUFVLHFCQUFWLENBQWI7QUFDQSxhQUFLLFFBQUwsR0FBZ0IsSUFBaEI7QUFDQSxhQUFLLFNBQUw7QUFDSDs7OztvQ0FFVztBQUNSLGlCQUFLLFFBQUwsR0FBZ0IsS0FBSyxHQUFMLEVBQWhCO0FBQ0g7Ozs7OztJQUdDLEs7QUFDRixtQkFBWSxRQUFaLEVBQXNCLE1BQXRCLEVBQThCLEtBQTlCLEVBQXFDO0FBQUE7O0FBQ2pDLGFBQUssU0FBTCxHQUFpQixRQUFqQjtBQUNBLGFBQUssT0FBTCxHQUFlLE1BQWY7QUFDQSxhQUFLLE1BQUwsR0FBYyxLQUFkO0FBQ0EsYUFBSyxLQUFMLEdBQWEsRUFBYixDO0FBQ0EsYUFBSyxZQUFMLEdBQW9CLHlCQUFwQixDO0FBQ0g7Ozs7NEJBRUcsRyxFQUFLLFEsRUFBVTtBQUFBOztBQUNmLGdCQUFJLEtBQUssS0FBTCxDQUFXLGNBQVgsQ0FBMEIsR0FBMUIsQ0FBSixFQUFvQztBQUNoQyxxQkFBSyxTQUFMLENBQWUsR0FBZjtBQUNBLG9CQUFNLFNBQVEsS0FBSyxLQUFMLENBQVcsR0FBWCxDQUFkO0FBQ0EsNkJBQWEsU0FBUyxJQUFULENBQWMsSUFBZCxFQUFvQixPQUFNLEtBQTFCLEVBQWlDLE9BQU0sT0FBdkMsQ0FBYjtBQUNBO0FBQ0g7O0FBRUQsZ0JBQU0sUUFBUSxJQUFJLFVBQUosRUFBZDtBQUNBLDRCQUFnQixLQUFLLFlBQXJCLEVBQW1DLE1BQU0sUUFBekMsRUFBbUQsR0FBbkQ7QUFDQSxpQkFBSyxLQUFMLENBQVcsR0FBWCxJQUFrQixLQUFsQjtBQUNBLGlCQUFLLG9CQUFMLENBQTBCLE1BQU0sUUFBaEM7O0FBRUEsaUJBQUssT0FBTCxDQUFhLEdBQWIsRUFBa0IsVUFBQyxLQUFELEVBQVEsT0FBUixFQUFvQjtBQUNsQyxzQkFBTSxLQUFOLEdBQWMsS0FBZDtBQUNBLHNCQUFNLE9BQU4sR0FBZ0IsT0FBaEI7O0FBRUEsb0JBQUksS0FBSixFQUFXOztBQUVQLDJCQUFPLE1BQUssS0FBTCxDQUFXLEdBQVgsQ0FBUDtBQUNBLG9DQUFnQixNQUFLLFlBQXJCLEVBQW1DLE1BQU0sUUFBekMsRUFBbUQsR0FBbkQ7QUFDSDs7QUFFRCx5QkFBUyxLQUFULEVBQWdCLE9BQWhCO0FBQ0gsYUFYRDtBQVlIOzs7c0NBRWEsSyxFQUFPO0FBQ2pCLGdCQUFJLE1BQU0sT0FBTixLQUFrQixJQUF0QixFQUE0QjtBQUN4QixvQkFBSTtBQUNBLHlCQUFLLE1BQUwsQ0FBWSxNQUFNLE9BQWxCO0FBQ0gsaUJBRkQsQ0FFRSxPQUFPLEVBQVAsRUFBVzs7QUFFWjtBQUNELHNCQUFNLE9BQU4sR0FBZ0IsSUFBaEI7QUFDQSxzQkFBTSxLQUFOLEdBQWMsSUFBSSxLQUFKLENBQVUsZ0JBQVYsQ0FBZDtBQUNIO0FBQ0o7OztrQ0FFUyxHLEVBQUs7QUFDWCxnQkFBSSxDQUFDLEtBQUssS0FBTCxDQUFXLGNBQVgsQ0FBMEIsR0FBMUIsQ0FBTCxFQUFxQztBQUNqQyx1QkFBTyxLQUFQO0FBQ0g7QUFDRCxnQkFBTSxRQUFRLEtBQUssS0FBTCxDQUFXLEdBQVgsQ0FBZDtBQUNBLDRCQUFnQixLQUFLLFlBQXJCLEVBQW1DLE1BQU0sUUFBekMsRUFBbUQsR0FBbkQ7QUFDQSxrQkFBTSxTQUFOO0FBQ0EsNEJBQWdCLEtBQUssWUFBckIsRUFBbUMsTUFBTSxRQUF6QyxFQUFtRCxHQUFuRDtBQUNBLGlCQUFLLG9CQUFMLENBQTBCLE1BQU0sUUFBaEM7QUFDQSxtQkFBTyxJQUFQO0FBQ0g7Ozs2Q0FFb0IsUSxFQUFVO0FBQzNCLGdCQUFJLEtBQUssWUFBTCxDQUFrQixLQUFsQixDQUF3QixHQUF4QixHQUE4QixDQUE5QixNQUFxQyxRQUF6QyxFQUFtRDs7QUFFL0M7QUFDSDtBQUNELGdCQUFNLFFBQVEsS0FBSyxZQUFMLENBQWtCLEdBQWxCLENBQXNCLFFBQXRCLEVBQWdDLEVBQWhDLENBQWQ7QUFDQSxnQkFBSSxNQUFNLE1BQU4sR0FBZSxDQUFuQixFQUFzQjs7QUFFbEI7QUFDSDtBQUNELGlCQUFLLFNBQUw7QUFDSDs7O29DQUVXO0FBQUE7O0FBQ1IsbUJBQU8sS0FBSyxZQUFMLENBQWtCLE1BQWxCLEtBQTZCLENBQXBDLEVBQXVDO0FBQ25DLG9CQUFNLFdBQVcsS0FBSyxZQUFMLENBQWtCLEtBQWxCLENBQXdCLEdBQXhCLEdBQThCLENBQTlCLENBQWpCO0FBQ0Esb0JBQU0sYUFBYSxXQUFXLEtBQUssU0FBbkM7QUFDQSxvQkFBSSxjQUFjLEtBQUssR0FBTCxFQUFsQixFQUE4Qjs7QUFFMUIsd0JBQU0sUUFBUSxLQUFLLFlBQUwsQ0FBa0IsR0FBbEIsQ0FBc0IsUUFBdEIsRUFBZ0MsRUFBaEMsQ0FBZDtBQUNBLHFDQUFPLE9BQVAsQ0FBZSxLQUFmLEVBQXNCLFVBQUMsR0FBRCxFQUFTO0FBQzNCLDRCQUFNLFFBQVEsT0FBSyxLQUFMLENBQVcsR0FBWCxDQUFkO0FBQ0EsK0JBQU8sT0FBSyxLQUFMLENBQVcsR0FBWCxDQUFQO0FBQ0EsK0JBQUssYUFBTCxDQUFtQixLQUFuQjtBQUNILHFCQUpEO0FBS0EseUJBQUssWUFBTCxDQUFrQixNQUFsQixDQUF5QixRQUF6QjtBQUNILGlCQVRELE1BU087O0FBRUgsd0JBQU0sY0FBYyxhQUFhLEtBQUssR0FBTCxFQUFqQztBQUNBLCtCQUFXLEtBQUssU0FBTCxDQUFlLElBQWYsQ0FBb0IsSUFBcEIsQ0FBWCxFQUFzQyxXQUF0QztBQUNBO0FBQ0g7QUFDSjtBQUNKOzs7Ozs7QUFHTCxTQUFTLGVBQVQsQ0FBeUIsR0FBekIsRUFBOEIsR0FBOUIsRUFBbUMsTUFBbkMsRUFBMkM7QUFDdkMsUUFBSSxDQUFDLElBQUksR0FBSixDQUFRLEdBQVIsQ0FBTCxFQUFtQjtBQUNmLFlBQUksR0FBSixDQUFRLEdBQVIsRUFBYSxDQUFDLE1BQUQsQ0FBYjtBQUNBO0FBQ0g7QUFDRCxRQUFNLFFBQVEsSUFBSSxHQUFKLENBQVEsR0FBUixDQUFkO0FBQ0EsVUFBTSxJQUFOLENBQVcsTUFBWDtBQUNBLFFBQUksR0FBSixDQUFRLEdBQVIsRUFBYSxLQUFiO0FBQ0g7O0FBRUQsU0FBUyxlQUFULENBQXlCLEdBQXpCLEVBQThCLEdBQTlCLEVBQW1DLE1BQW5DLEVBQTJDO0FBQ3ZDLFFBQUksQ0FBQyxJQUFJLEdBQUosQ0FBUSxHQUFSLENBQUwsRUFBbUI7QUFDZjtBQUNIO0FBQ0QsUUFBTSxRQUFRLElBQUksR0FBSixDQUFRLEdBQVIsQ0FBZDtBQUNBLFFBQU0sYUFBYSxpQkFBTyxPQUFQLENBQWUsS0FBZixFQUFzQixNQUF0QixDQUFuQjtBQUNBLFFBQUksZUFBZSxDQUFDLENBQXBCLEVBQXVCO0FBQ25CO0FBQ0g7QUFDRCxVQUFNLE1BQU4sQ0FBYSxVQUFiLEVBQXlCLENBQXpCO0FBQ0EsUUFBSSxNQUFNLE1BQU4sS0FBaUIsQ0FBckIsRUFBd0I7QUFDcEIsWUFBSSxNQUFKLENBQVcsR0FBWDtBQUNILEtBRkQsTUFFTztBQUNILFlBQUksR0FBSixDQUFRLEdBQVIsRUFBYSxLQUFiO0FBQ0g7QUFDSiIsImZpbGUiOiJncnBjcG9vbC5qcyIsInNvdXJjZXNDb250ZW50IjpbIlxuaW1wb3J0ICogYXMgY29tbW9uIGZyb20gJ2xldmVyb3MtY29tbW9uJztcbmltcG9ydCBncnBjIGZyb20gJ2dycGMnO1xuaW1wb3J0IGxvZGFzaCBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IFNvcnRlZE1hcCBmcm9tICdjb2xsZWN0aW9ucy9zb3J0ZWQtbWFwJztcblxuZXhwb3J0IGNsYXNzIEdSUENQb29sIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgY29uc3QgZXhwaXJ5TXMgPSA1ICogNjAgKiAxMDAwOyAgLy8gNSBtaW51dGVzIGluIG1zLlxuICAgICAgICB0aGlzLl9jb25ucyA9IG5ldyBDYWNoZShcbiAgICAgICAgICAgIGV4cGlyeU1zLCB0aGlzLl9uZXdDb25uLmJpbmQodGhpcyksIHRoaXMuX2Rlc3Ryb3lDb25uLmJpbmQodGhpcykpO1xuICAgIH1cblxuICAgIGRpYWwodGFyZ2V0LCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLl9jb25ucy5nZXQodGFyZ2V0LCBjYWxsYmFjayk7XG4gICAgfVxuXG4gICAga2VlcEFsaXZlKHRhcmdldCkge1xuICAgICAgICB0aGlzLl9jb25ucy5rZWVwQWxpdmUodGFyZ2V0KTtcbiAgICB9XG5cbiAgICBfbmV3Q29ubih0YXJnZXQsIGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrKFxuICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgIG5ldyBjb21tb24ubGV2ZXJSUENQcm90by5jb3JlLkxldmVyUlBDKFxuICAgICAgICAgICAgICAgIHRhcmdldCwgZ3JwYy5jcmVkZW50aWFscy5jcmVhdGVJbnNlY3VyZSgpKSk7XG4gICAgfVxuXG4gICAgX2Rlc3Ryb3lDb25uKGNvbm4pIHtcbiAgICAgICAgY29ubi4kY2hhbm5lbC5jbG9zZSgpO1xuICAgIH1cbn1cblxuY2xhc3MgQ2FjaGVFbnRyeSB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZWxlbWVudCA9IG51bGw7XG4gICAgICAgIHRoaXMuZXJyb3IgPSBuZXcgRXJyb3IoXCJOb3QgeWV0IGNvbnN0cnVjdGVkXCIpO1xuICAgICAgICB0aGlzLmxhc3RVc2VkID0gbnVsbDtcbiAgICAgICAgdGhpcy5rZWVwQWxpdmUoKTtcbiAgICB9XG5cbiAgICBrZWVwQWxpdmUoKSB7XG4gICAgICAgIHRoaXMubGFzdFVzZWQgPSBEYXRlLm5vdygpO1xuICAgIH1cbn1cblxuY2xhc3MgQ2FjaGUge1xuICAgIGNvbnN0cnVjdG9yKGV4cGlyeU1zLCBjb25zdHIsIGRlc3RyKSB7XG4gICAgICAgIHRoaXMuX2V4cGlyeU1zID0gZXhwaXJ5TXM7XG4gICAgICAgIHRoaXMuX2NvbnN0ciA9IGNvbnN0cjtcbiAgICAgICAgdGhpcy5fZGVzdHIgPSBkZXN0cjtcbiAgICAgICAgdGhpcy5fZGF0YSA9IHt9OyAgLy8ga2V5IC0+IENhY2hlRW50cnlcbiAgICAgICAgdGhpcy5fbGFzdFVzZWRNYXAgPSBuZXcgU29ydGVkTWFwKCk7ICAvLyBsYXN0VXNlZCAobXMpIC0+IGFycmF5IG9mIGtleXNcbiAgICB9XG5cbiAgICBnZXQoa2V5LCBjYWxsYmFjaykge1xuICAgICAgICBpZiAodGhpcy5fZGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICB0aGlzLmtlZXBBbGl2ZShrZXkpO1xuICAgICAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLl9kYXRhW2tleV07XG4gICAgICAgICAgICBzZXRJbW1lZGlhdGUoY2FsbGJhY2suYmluZChudWxsLCBlbnRyeS5lcnJvciwgZW50cnkuZWxlbWVudCkpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZW50cnkgPSBuZXcgQ2FjaGVFbnRyeSgpO1xuICAgICAgICBzb3J0ZWRNYXBJbnNlcnQodGhpcy5fbGFzdFVzZWRNYXAsIGVudHJ5Lmxhc3RVc2VkLCBrZXkpO1xuICAgICAgICB0aGlzLl9kYXRhW2tleV0gPSBlbnRyeTtcbiAgICAgICAgdGhpcy5fbWF5YmVTY2hlZHVsZUV4cGlyZShlbnRyeS5sYXN0VXNlZCk7XG5cbiAgICAgICAgdGhpcy5fY29uc3RyKGtleSwgKGVycm9yLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICBlbnRyeS5lcnJvciA9IGVycm9yO1xuICAgICAgICAgICAgZW50cnkuZWxlbWVudCA9IGVsZW1lbnQ7XG5cbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBmcm9tIGNhY2hlIGlmIGNvbnN0cnVjdGlvbiBmYWlsZWQuXG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuX2RhdGFba2V5XTtcbiAgICAgICAgICAgICAgICBzb3J0ZWRNYXBSZW1vdmUodGhpcy5fbGFzdFVzZWRNYXAsIGVudHJ5Lmxhc3RVc2VkLCBrZXkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjYWxsYmFjayhlcnJvciwgZWxlbWVudCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIF9kZXN0cm95RW50cnkoZW50cnkpIHtcbiAgICAgICAgaWYgKGVudHJ5LmVsZW1lbnQgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVzdHIoZW50cnkuZWxlbWVudCk7XG4gICAgICAgICAgICB9IGNhdGNoIChleCkge1xuICAgICAgICAgICAgICAgIC8vIERvIG5vdGhpbmcuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbnRyeS5lbGVtZW50ID0gbnVsbDtcbiAgICAgICAgICAgIGVudHJ5LmVycm9yID0gbmV3IEVycm9yKFwiV2FzIGRlc3RydWN0ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBrZWVwQWxpdmUoa2V5KSB7XG4gICAgICAgIGlmICghdGhpcy5fZGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLl9kYXRhW2tleV07XG4gICAgICAgIHNvcnRlZE1hcFJlbW92ZSh0aGlzLl9sYXN0VXNlZE1hcCwgZW50cnkubGFzdFVzZWQsIGtleSk7XG4gICAgICAgIGVudHJ5LmtlZXBBbGl2ZSgpO1xuICAgICAgICBzb3J0ZWRNYXBJbnNlcnQodGhpcy5fbGFzdFVzZWRNYXAsIGVudHJ5Lmxhc3RVc2VkLCBrZXkpO1xuICAgICAgICB0aGlzLl9tYXliZVNjaGVkdWxlRXhwaXJlKGVudHJ5Lmxhc3RVc2VkKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgX21heWJlU2NoZWR1bGVFeHBpcmUobGFzdFVzZWQpIHtcbiAgICAgICAgaWYgKHRoaXMuX2xhc3RVc2VkTWFwLnN0b3JlLm1pbigpWzBdICE9PSBsYXN0VXNlZCkge1xuICAgICAgICAgICAgLy8gQWxyZWFkeSBzY2hlZHVsZWQuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLl9sYXN0VXNlZE1hcC5nZXQobGFzdFVzZWQsIFtdKTtcbiAgICAgICAgaWYgKHZhbHVlLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIC8vIEFscmVhZHkgc2NoZWR1bGVkLlxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2RvRXhwaXJlKCk7XG4gICAgfVxuXG4gICAgX2RvRXhwaXJlKCkge1xuICAgICAgICB3aGlsZSAodGhpcy5fbGFzdFVzZWRNYXAubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0VXNlZCA9IHRoaXMuX2xhc3RVc2VkTWFwLnN0b3JlLm1pbigpWzBdO1xuICAgICAgICAgICAgY29uc3QgZXhwaXJ5VGltZSA9IGxhc3RVc2VkICsgdGhpcy5fZXhwaXJ5TXM7XG4gICAgICAgICAgICBpZiAoZXhwaXJ5VGltZSA8PSBEYXRlLm5vdygpKSB7XG4gICAgICAgICAgICAgICAgLy8gRW50cnkgZXhwaXJlZC5cbiAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuX2xhc3RVc2VkTWFwLmdldChsYXN0VXNlZCwgW10pO1xuICAgICAgICAgICAgICAgIGxvZGFzaC5mb3JFYWNoKHZhbHVlLCAoa2V5KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5fZGF0YVtrZXldO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5fZGF0YVtrZXldO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9kZXN0cm95RW50cnkoZW50cnkpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX2xhc3RVc2VkTWFwLmRlbGV0ZShsYXN0VXNlZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIE5vdCB5ZXQgdGltZS4gU2NoZWR1bGUgbmV4dC5cbiAgICAgICAgICAgICAgICBjb25zdCB1bnRpbEV4cGlyeSA9IGV4cGlyeVRpbWUgLSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQodGhpcy5fZG9FeHBpcmUuYmluZCh0aGlzKSwgdW50aWxFeHBpcnkpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cblxuZnVuY3Rpb24gc29ydGVkTWFwSW5zZXJ0KG1hcCwga2V5LCB0YXJnZXQpIHtcbiAgICBpZiAoIW1hcC5oYXMoa2V5KSkge1xuICAgICAgICBtYXAuc2V0KGtleSwgW3RhcmdldF0pO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHZhbHVlID0gbWFwLmdldChrZXkpO1xuICAgIHZhbHVlLnB1c2godGFyZ2V0KTtcbiAgICBtYXAuc2V0KGtleSwgdmFsdWUpO1xufVxuXG5mdW5jdGlvbiBzb3J0ZWRNYXBSZW1vdmUobWFwLCBrZXksIHRhcmdldCkge1xuICAgIGlmICghbWFwLmhhcyhrZXkpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgdmFsdWUgPSBtYXAuZ2V0KGtleSk7XG4gICAgY29uc3QgZm91bmRJbmRleCA9IGxvZGFzaC5pbmRleE9mKHZhbHVlLCB0YXJnZXQpO1xuICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHZhbHVlLnNwbGljZShmb3VuZEluZGV4LCAxKTtcbiAgICBpZiAodmFsdWUubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIG1hcC5kZWxldGUoa2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBtYXAuc2V0KGtleSwgdmFsdWUpO1xuICAgIH1cbn1cbiJdfQ==