1 | 'use strict';
|
2 |
|
3 | Object.defineProperty(exports, "__esModule", {
|
4 | value: true
|
5 | });
|
6 |
|
7 | var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
|
8 |
|
9 | var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
|
10 |
|
11 | var _promise = require('babel-runtime/core-js/promise');
|
12 |
|
13 | var _promise2 = _interopRequireDefault(_promise);
|
14 |
|
15 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
|
16 |
|
17 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
|
18 |
|
19 | var _createClass2 = require('babel-runtime/helpers/createClass');
|
20 |
|
21 | var _createClass3 = _interopRequireDefault(_createClass2);
|
22 |
|
23 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
24 |
|
25 | var debug = require('debug')('graphbrainz:rate-limit');
|
26 |
|
27 | var RateLimit = function () {
|
28 | function RateLimit() {
|
29 | var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
|
30 | _ref$limit = _ref.limit,
|
31 | limit = _ref$limit === undefined ? 1 : _ref$limit,
|
32 | _ref$period = _ref.period,
|
33 | period = _ref$period === undefined ? 1000 : _ref$period,
|
34 | _ref$concurrency = _ref.concurrency,
|
35 | concurrency = _ref$concurrency === undefined ? limit || 1 : _ref$concurrency,
|
36 | _ref$defaultPriority = _ref.defaultPriority,
|
37 | defaultPriority = _ref$defaultPriority === undefined ? 1 : _ref$defaultPriority;
|
38 |
|
39 | (0, _classCallCheck3.default)(this, RateLimit);
|
40 |
|
41 | this.limit = limit;
|
42 | this.period = period;
|
43 | this.defaultPriority = defaultPriority;
|
44 | this.concurrency = concurrency;
|
45 | this.queues = [];
|
46 | this.numPending = 0;
|
47 | this.periodStart = null;
|
48 | this.periodCapacity = this.limit;
|
49 | this.timer = null;
|
50 | this.pendingFlush = false;
|
51 | this.prevTaskID = null;
|
52 | }
|
53 |
|
54 | (0, _createClass3.default)(RateLimit, [{
|
55 | key: 'nextTaskID',
|
56 | value: function nextTaskID() {
|
57 | var prevTaskID = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.prevTaskID;
|
58 |
|
59 | var id = (prevTaskID || 0) + 1;
|
60 | this.prevTaskID = id;
|
61 | return id;
|
62 | }
|
63 | }, {
|
64 | key: 'enqueue',
|
65 | value: function enqueue(fn, args) {
|
66 | var _this = this;
|
67 |
|
68 | var priority = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.defaultPriority;
|
69 |
|
70 | priority = Math.max(0, priority);
|
71 | return new _promise2.default(function (resolve, reject) {
|
72 | var queue = _this.queues[priority] = _this.queues[priority] || [];
|
73 | var id = _this.nextTaskID();
|
74 | debug('Enqueuing task. id=' + id + ' priority=' + priority);
|
75 | queue.push({ fn: fn, args: args, resolve: resolve, reject: reject, id: id });
|
76 | if (!_this.pendingFlush) {
|
77 | _this.pendingFlush = true;
|
78 | process.nextTick(function () {
|
79 | _this.pendingFlush = false;
|
80 | _this.flush();
|
81 | });
|
82 | }
|
83 | });
|
84 | }
|
85 | }, {
|
86 | key: 'dequeue',
|
87 | value: function dequeue() {
|
88 | var task = void 0;
|
89 | for (var i = this.queues.length - 1; i >= 0; i--) {
|
90 | var queue = this.queues[i];
|
91 | if (queue && queue.length) {
|
92 | task = queue.shift();
|
93 | }
|
94 | if (!queue || !queue.length) {
|
95 | this.queues.length = i;
|
96 | }
|
97 | if (task) {
|
98 | break;
|
99 | }
|
100 | }
|
101 | return task;
|
102 | }
|
103 | }, {
|
104 | key: 'flush',
|
105 | value: function flush() {
|
106 | var _this2 = this;
|
107 |
|
108 | if (this.numPending < this.concurrency && this.periodCapacity > 0) {
|
109 | var task = this.dequeue();
|
110 | if (task) {
|
111 | var resolve = task.resolve,
|
112 | reject = task.reject,
|
113 | fn = task.fn,
|
114 | args = task.args,
|
115 | id = task.id;
|
116 |
|
117 | if (this.timer == null) {
|
118 | var now = Date.now();
|
119 | var timeout = this.period;
|
120 | if (this.periodStart != null) {
|
121 | var delay = now - (this.periodStart + timeout);
|
122 | if (delay > 0 && delay <= timeout) {
|
123 | timeout -= delay;
|
124 | }
|
125 | }
|
126 | this.periodStart = now;
|
127 | this.timer = setTimeout(function () {
|
128 | _this2.timer = null;
|
129 | _this2.periodCapacity = _this2.limit;
|
130 | _this2.flush();
|
131 | }, timeout);
|
132 | }
|
133 | this.numPending += 1;
|
134 | this.periodCapacity -= 1;
|
135 | var onResolve = function onResolve(value) {
|
136 | _this2.numPending -= 1;
|
137 | resolve(value);
|
138 | _this2.flush();
|
139 | };
|
140 | var onReject = function onReject(err) {
|
141 | _this2.numPending -= 1;
|
142 | reject(err);
|
143 | _this2.flush();
|
144 | };
|
145 | debug('Running task. id=' + id);
|
146 | fn.apply(undefined, (0, _toConsumableArray3.default)(args)).then(onResolve, onReject);
|
147 | this.flush();
|
148 | }
|
149 | }
|
150 | }
|
151 | }]);
|
152 | return RateLimit;
|
153 | }();
|
154 |
|
155 | exports.default = RateLimit; |
\ | No newline at end of file |