leveros
Version:
The Lever OS Node client library
223 lines (189 loc) • 18.8 kB
JavaScript
'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,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QXBCLEVBQXVCO0FBQ25CO0FBQ0g7QUFDRCxVQUFNLE1BQU4sQ0FBYSxVQUFiLEVBQXlCLENBQXpCO0FBQ0EsUUFBSSxNQUFNLE1BQU4sS0FBaUIsQ0FBckIsRUFBd0I7QUFDcEIsWUFBSSxNQUFKLENBQVcsR0FBWDtBQUNILEtBRkQsTUFFTztBQUNILFlBQUksR0FBSixDQUFRLEdBQVIsRUFBYSxLQUFiO0FBQ0g7QUFDSiIsImZpbGUiOiJncnBjcG9vbC5qcyIsInNvdXJjZXNDb250ZW50IjpbIlxuaW1wb3J0ICogYXMgY29tbW9uIGZyb20gJ2xldmVyb3MtY29tbW9uJztcbmltcG9ydCBncnBjIGZyb20gJ2dycGMnO1xuaW1wb3J0IGxvZGFzaCBmcm9tICdsb2Rhc2gnO1xuaW1wb3J0IFNvcnRlZE1hcCBmcm9tICdjb2xsZWN0aW9ucy9zb3J0ZWQtbWFwJztcblxuZXhwb3J0IGNsYXNzIEdSUENQb29sIHtcbiAgICBjb25zdHJ1Y3RvcigpIHtcbiAgICAgICAgY29uc3QgZXhwaXJ5TXMgPSA1ICogNjAgKiAxMDAwOyAgLy8gNSBtaW51dGVzIGluIG1zLlxuICAgICAgICB0aGlzLl9jb25ucyA9IG5ldyBDYWNoZShcbiAgICAgICAgICAgIGV4cGlyeU1zLCB0aGlzLl9uZXdDb25uLmJpbmQodGhpcyksIHRoaXMuX2Rlc3Ryb3lDb25uLmJpbmQodGhpcykpO1xuICAgIH1cblxuICAgIGRpYWwodGFyZ2V0LCBjYWxsYmFjaykge1xuICAgICAgICB0aGlzLl9jb25ucy5nZXQodGFyZ2V0LCBjYWxsYmFjayk7XG4gICAgfVxuXG4gICAga2VlcEFsaXZlKHRhcmdldCkge1xuICAgICAgICB0aGlzLl9jb25ucy5rZWVwQWxpdmUodGFyZ2V0KTtcbiAgICB9XG5cbiAgICBfbmV3Q29ubih0YXJnZXQsIGNhbGxiYWNrKSB7XG4gICAgICAgIGNhbGxiYWNrKFxuICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgIG5ldyBjb21tb24ubGV2ZXJSUENQcm90by5jb3JlLkxldmVyUlBDKFxuICAgICAgICAgICAgICAgIHRhcmdldCwgZ3JwYy5jcmVkZW50aWFscy5jcmVhdGVJbnNlY3VyZSgpKSk7XG4gICAgfVxuXG4gICAgX2Rlc3Ryb3lDb25uKGNvbm4pIHtcbiAgICAgICAgY29ubi4kY2hhbm5lbC5jbG9zZSgpO1xuICAgIH1cbn1cblxuY2xhc3MgQ2FjaGVFbnRyeSB7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuZWxlbWVudCA9IG51bGw7XG4gICAgICAgIHRoaXMuZXJyb3IgPSBuZXcgRXJyb3IoXCJOb3QgeWV0IGNvbnN0cnVjdGVkXCIpO1xuICAgICAgICB0aGlzLmxhc3RVc2VkID0gbnVsbDtcbiAgICAgICAgdGhpcy5rZWVwQWxpdmUoKTtcbiAgICB9XG5cbiAgICBrZWVwQWxpdmUoKSB7XG4gICAgICAgIHRoaXMubGFzdFVzZWQgPSBEYXRlLm5vdygpO1xuICAgIH1cbn1cblxuY2xhc3MgQ2FjaGUge1xuICAgIGNvbnN0cnVjdG9yKGV4cGlyeU1zLCBjb25zdHIsIGRlc3RyKSB7XG4gICAgICAgIHRoaXMuX2V4cGlyeU1zID0gZXhwaXJ5TXM7XG4gICAgICAgIHRoaXMuX2NvbnN0ciA9IGNvbnN0cjtcbiAgICAgICAgdGhpcy5fZGVzdHIgPSBkZXN0cjtcbiAgICAgICAgdGhpcy5fZGF0YSA9IHt9OyAgLy8ga2V5IC0+IENhY2hlRW50cnlcbiAgICAgICAgdGhpcy5fbGFzdFVzZWRNYXAgPSBuZXcgU29ydGVkTWFwKCk7ICAvLyBsYXN0VXNlZCAobXMpIC0+IGFycmF5IG9mIGtleXNcbiAgICB9XG5cbiAgICBnZXQoa2V5LCBjYWxsYmFjaykge1xuICAgICAgICBpZiAodGhpcy5fZGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICB0aGlzLmtlZXBBbGl2ZShrZXkpO1xuICAgICAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLl9kYXRhW2tleV07XG4gICAgICAgICAgICBzZXRJbW1lZGlhdGUoY2FsbGJhY2suYmluZChudWxsLCBlbnRyeS5lcnJvciwgZW50cnkuZWxlbWVudCkpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgZW50cnkgPSBuZXcgQ2FjaGVFbnRyeSgpO1xuICAgICAgICBzb3J0ZWRNYXBJbnNlcnQodGhpcy5fbGFzdFVzZWRNYXAsIGVudHJ5Lmxhc3RVc2VkLCBrZXkpO1xuICAgICAgICB0aGlzLl9kYXRhW2tleV0gPSBlbnRyeTtcbiAgICAgICAgdGhpcy5fbWF5YmVTY2hlZHVsZUV4cGlyZShlbnRyeS5sYXN0VXNlZCk7XG5cbiAgICAgICAgdGhpcy5fY29uc3RyKGtleSwgKGVycm9yLCBlbGVtZW50KSA9PiB7XG4gICAgICAgICAgICBlbnRyeS5lcnJvciA9IGVycm9yO1xuICAgICAgICAgICAgZW50cnkuZWxlbWVudCA9IGVsZW1lbnQ7XG5cbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBmcm9tIGNhY2hlIGlmIGNvbnN0cnVjdGlvbiBmYWlsZWQuXG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuX2RhdGFba2V5XTtcbiAgICAgICAgICAgICAgICBzb3J0ZWRNYXBSZW1vdmUodGhpcy5fbGFzdFVzZWRNYXAsIGVudHJ5Lmxhc3RVc2VkLCBrZXkpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjYWxsYmFjayhlcnJvciwgZWxlbWVudCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIF9kZXN0cm95RW50cnkoZW50cnkpIHtcbiAgICAgICAgaWYgKGVudHJ5LmVsZW1lbnQgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fZGVzdHIoZW50cnkuZWxlbWVudCk7XG4gICAgICAgICAgICB9IGNhdGNoIChleCkge1xuICAgICAgICAgICAgICAgIC8vIERvIG5vdGhpbmcuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbnRyeS5lbGVtZW50ID0gbnVsbDtcbiAgICAgICAgICAgIGVudHJ5LmVycm9yID0gbmV3IEVycm9yKFwiV2FzIGRlc3RydWN0ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBrZWVwQWxpdmUoa2V5KSB7XG4gICAgICAgIGlmICghdGhpcy5fZGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZW50cnkgPSB0aGlzLl9kYXRhW2tleV07XG4gICAgICAgIHNvcnRlZE1hcFJlbW92ZSh0aGlzLl9sYXN0VXNlZE1hcCwgZW50cnkubGFzdFVzZWQsIGtleSk7XG4gICAgICAgIGVudHJ5LmtlZXBBbGl2ZSgpO1xuICAgICAgICBzb3J0ZWRNYXBJbnNlcnQodGhpcy5fbGFzdFVzZWRNYXAsIGVudHJ5Lmxhc3RVc2VkLCBrZXkpO1xuICAgICAgICB0aGlzLl9tYXliZVNjaGVkdWxlRXhwaXJlKGVudHJ5Lmxhc3RVc2VkKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuXG4gICAgX21heWJlU2NoZWR1bGVFeHBpcmUobGFzdFVzZWQpIHtcbiAgICAgICAgaWYgKHRoaXMuX2xhc3RVc2VkTWFwLnN0b3JlLm1pbigpWzBdICE9PSBsYXN0VXNlZCkge1xuICAgICAgICAgICAgLy8gQWxyZWFkeSBzY2hlZHVsZWQuXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdmFsdWUgPSB0aGlzLl9sYXN0VXNlZE1hcC5nZXQobGFzdFVzZWQsIFtdKTtcbiAgICAgICAgaWYgKHZhbHVlLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIC8vIEFscmVhZHkgc2NoZWR1bGVkLlxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2RvRXhwaXJlKCk7XG4gICAgfVxuXG4gICAgX2RvRXhwaXJlKCkge1xuICAgICAgICB3aGlsZSAodGhpcy5fbGFzdFVzZWRNYXAubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgICAgICBjb25zdCBsYXN0VXNlZCA9IHRoaXMuX2xhc3RVc2VkTWFwLnN0b3JlLm1pbigpWzBdO1xuICAgICAgICAgICAgY29uc3QgZXhwaXJ5VGltZSA9IGxhc3RVc2VkICsgdGhpcy5fZXhwaXJ5TXM7XG4gICAgICAgICAgICBpZiAoZXhwaXJ5VGltZSA8PSBEYXRlLm5vdygpKSB7XG4gICAgICAgICAgICAgICAgLy8gRW50cnkgZXhwaXJlZC5cbiAgICAgICAgICAgICAgICBjb25zdCB2YWx1ZSA9IHRoaXMuX2xhc3RVc2VkTWFwLmdldChsYXN0VXNlZCwgW10pO1xuICAgICAgICAgICAgICAgIGxvZGFzaC5mb3JFYWNoKHZhbHVlLCAoa2V5KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGVudHJ5ID0gdGhpcy5fZGF0YVtrZXldO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5fZGF0YVtrZXldO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9kZXN0cm95RW50cnkoZW50cnkpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX2xhc3RVc2VkTWFwLmRlbGV0ZShsYXN0VXNlZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIE5vdCB5ZXQgdGltZS4gU2NoZWR1bGUgbmV4dC5cbiAgICAgICAgICAgICAgICBjb25zdCB1bnRpbEV4cGlyeSA9IGV4cGlyeVRpbWUgLSBEYXRlLm5vdygpO1xuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQodGhpcy5fZG9FeHBpcmUuYmluZCh0aGlzKSwgdW50aWxFeHBpcnkpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbn1cblxuZnVuY3Rpb24gc29ydGVkTWFwSW5zZXJ0KG1hcCwga2V5LCB0YXJnZXQpIHtcbiAgICBpZiAoIW1hcC5oYXMoa2V5KSkge1xuICAgICAgICBtYXAuc2V0KGtleSwgW3RhcmdldF0pO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnN0IHZhbHVlID0gbWFwLmdldChrZXkpO1xuICAgIHZhbHVlLnB1c2godGFyZ2V0KTtcbiAgICBtYXAuc2V0KGtleSwgdmFsdWUpO1xufVxuXG5mdW5jdGlvbiBzb3J0ZWRNYXBSZW1vdmUobWFwLCBrZXksIHRhcmdldCkge1xuICAgIGlmICghbWFwLmhhcyhrZXkpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgdmFsdWUgPSBtYXAuZ2V0KGtleSk7XG4gICAgY29uc3QgZm91bmRJbmRleCA9IGxvZGFzaC5pbmRleE9mKHZhbHVlLCB0YXJnZXQpO1xuICAgIGlmIChmb3VuZEluZGV4ID09PSAtMSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIHZhbHVlLnNwbGljZShmb3VuZEluZGV4LCAxKTtcbiAgICBpZiAodmFsdWUubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIG1hcC5kZWxldGUoa2V5KTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBtYXAuc2V0KGtleSwgdmFsdWUpO1xuICAgIH1cbn1cbiJdfQ==