@withjoy/limiter 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/limiter.js +49 -30
- package/package.json +1 -1
- package/tests/limiter.test.js +90 -91
- package/tests/performTestWithTestPerMinute.js +5 -4
- package/tests/sanityCheck.js +33 -28
package/limiter.js
CHANGED
|
@@ -42,10 +42,8 @@ class Limiter {
|
|
|
42
42
|
// static pickDefaultBuckets(keys) { ... };
|
|
43
43
|
|
|
44
44
|
constructor(config) {
|
|
45
|
-
this._console = config.console;
|
|
46
45
|
this._config = config;
|
|
47
|
-
this.
|
|
48
|
-
this._limitdRedis = this.connect();
|
|
46
|
+
this._limitdRedisConnectionPromise = this.connect();
|
|
49
47
|
}
|
|
50
48
|
|
|
51
49
|
/*
|
|
@@ -54,21 +52,54 @@ class Limiter {
|
|
|
54
52
|
stub it to prevent a real connect from happening under Test Suite Conditions
|
|
55
53
|
*/
|
|
56
54
|
connect() {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
connection
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
return new Promise((resolve, reject) => {
|
|
56
|
+
let buckets = this._config.buckets || {};
|
|
57
|
+
buckets = {
|
|
58
|
+
...defaultBuckets,
|
|
59
|
+
...buckets,
|
|
60
|
+
};
|
|
61
|
+
const keyPrefix = this._config.keyPrefix || defaultRedisKeyPrefix;
|
|
62
|
+
if (!connection) {
|
|
63
|
+
connection = new LimitdRedis({
|
|
64
|
+
uri: this._config.limitdUrl,
|
|
65
|
+
buckets,
|
|
66
|
+
keyPrefix,
|
|
67
|
+
});
|
|
68
|
+
connection.db.on('ready', () => {
|
|
69
|
+
return resolve(connection);
|
|
70
|
+
});
|
|
71
|
+
} else {
|
|
72
|
+
return resolve(connection);
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async getLimiterProcessor(console) {
|
|
78
|
+
await this._limitdRedisConnectionPromise;
|
|
79
|
+
return new LimiterProcessor(console);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
close() {
|
|
83
|
+
return new Promise(async (resolve, reject) => {
|
|
84
|
+
const connectionPromise = await this._limitdRedisConnectionPromise;
|
|
85
|
+
connectionPromise.close((err, resp) => {
|
|
86
|
+
if (err) {
|
|
87
|
+
this._console.error(err);
|
|
88
|
+
return reject(err);
|
|
89
|
+
}
|
|
90
|
+
console.log("Connection closed");
|
|
91
|
+
resolve(resp);
|
|
68
92
|
});
|
|
69
|
-
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
class LimiterProcessor {
|
|
98
|
+
|
|
99
|
+
constructor(console) {
|
|
100
|
+
this._console = console;
|
|
101
|
+
this._operationList = [];
|
|
70
102
|
this._limitdRedis = connection;
|
|
71
|
-
return connection;
|
|
72
103
|
}
|
|
73
104
|
|
|
74
105
|
/*
|
|
@@ -97,18 +128,6 @@ class Limiter {
|
|
|
97
128
|
this._operationList.push(op);
|
|
98
129
|
}
|
|
99
130
|
|
|
100
|
-
close() {
|
|
101
|
-
return new Promise((resolve, reject) => {
|
|
102
|
-
this._limitdRedis.close((err, resp) => {
|
|
103
|
-
if (err) {
|
|
104
|
-
this._console.error(err);
|
|
105
|
-
return reject(err);
|
|
106
|
-
}
|
|
107
|
-
console.log("Connection closed");
|
|
108
|
-
resolve(resp);
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
131
|
// promise wrapper for limitd lib put
|
|
113
132
|
_put(type, id, amount) {
|
|
114
133
|
return new Promise((resolve, reject) =>
|
|
@@ -173,12 +192,12 @@ Limiter.pickDefaultBuckets = function pickDefaultBuckets(keyArray) {
|
|
|
173
192
|
const buckets = {};
|
|
174
193
|
for (const key of keyArray) {
|
|
175
194
|
const bucket = defaultBuckets[key];
|
|
176
|
-
if (!
|
|
195
|
+
if (!bucket) {
|
|
177
196
|
throw new Error(`Limiter.pickDefaultBuckets: no such bucket; "${key}"`);
|
|
178
197
|
}
|
|
179
198
|
buckets[key] = defaultBuckets[key];
|
|
180
199
|
}
|
|
181
200
|
return buckets;
|
|
182
|
-
}
|
|
201
|
+
};
|
|
183
202
|
|
|
184
203
|
module.exports = Limiter;
|
package/package.json
CHANGED
package/tests/limiter.test.js
CHANGED
|
@@ -16,15 +16,14 @@ const TEST_BUCKETS = {
|
|
|
16
16
|
The limitd service is essentially a token bank
|
|
17
17
|
that we can withdraw from (take) or deposit to (put)
|
|
18
18
|
*/
|
|
19
|
-
const limiterWithMockService = (succeeds = true, conforms = true) => {
|
|
19
|
+
const limiterWithMockService = async (succeeds = true, conforms = true) => {
|
|
20
20
|
let token_pile = 0;
|
|
21
21
|
const limiter = new Limiter({
|
|
22
|
-
console: console,
|
|
23
22
|
limitdUrl: "localhost:6379",
|
|
24
23
|
buckets: TEST_BUCKETS,
|
|
25
24
|
});
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
26
|
+
limiterProcessor._limitdRedis = new (class MockLimitd {
|
|
28
27
|
constructor(should_succeed, should_conform) {
|
|
29
28
|
this.should_succeed = should_succeed;
|
|
30
29
|
this.should_conform = should_conform;
|
|
@@ -52,38 +51,38 @@ const limiterWithMockService = (succeeds = true, conforms = true) => {
|
|
|
52
51
|
return token_pile;
|
|
53
52
|
}
|
|
54
53
|
})(succeeds, conforms);
|
|
55
|
-
return
|
|
54
|
+
return limiterProcessor;
|
|
56
55
|
};
|
|
57
56
|
|
|
58
57
|
test("perfrom limitd-redis testing with test bucket", async (done) => {
|
|
59
58
|
const limiter = new Limiter({
|
|
60
59
|
limitdUrl: "localhost:6379",
|
|
61
|
-
console: console,
|
|
62
60
|
buckets: {
|
|
63
61
|
test: { size: 3, per_second: 2 },
|
|
64
62
|
},
|
|
65
|
-
})
|
|
63
|
+
})
|
|
64
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
66
65
|
// take 2 # Conformant - Remaining: 1
|
|
67
|
-
const result1 = await
|
|
66
|
+
const result1 = await limiterProcessor.transfer("test", "test-key", 2);
|
|
68
67
|
expect(result1).toMatchObject({
|
|
69
68
|
conformant: true,
|
|
70
69
|
remaining: 1,
|
|
71
70
|
limit: 3,
|
|
72
71
|
delayed: false,
|
|
73
72
|
});
|
|
74
|
-
await expect(
|
|
73
|
+
await expect(limiterProcessor.transfer("test", "test-key", 2)).rejects.toThrow(
|
|
75
74
|
"Non Conformant"
|
|
76
75
|
);
|
|
77
76
|
|
|
78
77
|
// Put 1
|
|
79
|
-
const result3 = await
|
|
78
|
+
const result3 = await limiterProcessor.transfer("test", "test-key", -1);
|
|
80
79
|
expect(result3).toMatchObject({
|
|
81
80
|
remaining: 2,
|
|
82
81
|
limit: 3,
|
|
83
82
|
});
|
|
84
83
|
|
|
85
84
|
//Now Conformant - Remaining: 2
|
|
86
|
-
const result4 = await
|
|
85
|
+
const result4 = await limiterProcessor.transfer("test", "test-key", 2);
|
|
87
86
|
expect(result4).toMatchObject({
|
|
88
87
|
conformant: true,
|
|
89
88
|
remaining: 0,
|
|
@@ -94,177 +93,177 @@ test("perfrom limitd-redis testing with test bucket", async (done) => {
|
|
|
94
93
|
done();
|
|
95
94
|
});
|
|
96
95
|
|
|
97
|
-
test("Resolves to null if we aren't doing a real transfer", (done) => {
|
|
98
|
-
let
|
|
99
|
-
|
|
96
|
+
test("Resolves to null if we aren't doing a real transfer", async (done) => {
|
|
97
|
+
let limiterProcessor = await limiterWithMockService();
|
|
98
|
+
limiterProcessor.transfer("a", "b", 0, null).then((result) => {
|
|
100
99
|
expect(result).toBe(null);
|
|
101
|
-
expect(
|
|
100
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
102
101
|
done();
|
|
103
102
|
});
|
|
104
103
|
});
|
|
105
104
|
|
|
106
|
-
test("Adds tokens if provided a negative token amount", (done) => {
|
|
107
|
-
let
|
|
108
|
-
|
|
105
|
+
test("Adds tokens if provided a negative token amount", async (done) => {
|
|
106
|
+
let limiterProcessor = await limiterWithMockService();
|
|
107
|
+
limiterProcessor.transfer("a", "b", -5).then((result) => {
|
|
109
108
|
expect(result).toMatchObject({});
|
|
110
|
-
expect(
|
|
109
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
111
110
|
done();
|
|
112
111
|
});
|
|
113
112
|
});
|
|
114
113
|
|
|
115
|
-
test("Removes tokens if provided a positive token amount", (done) => {
|
|
116
|
-
let
|
|
117
|
-
|
|
114
|
+
test("Removes tokens if provided a positive token amount", async (done) => {
|
|
115
|
+
let limiterProcessor = await limiterWithMockService();
|
|
116
|
+
limiterProcessor.transfer("a", "b", 5).then((result) => {
|
|
118
117
|
expect(result).toMatchObject({ conformant: true });
|
|
119
|
-
expect(
|
|
118
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(-5);
|
|
120
119
|
done();
|
|
121
120
|
});
|
|
122
121
|
});
|
|
123
122
|
|
|
124
|
-
test("Reverts all taken tokens when revert is called", (done) => {
|
|
125
|
-
let
|
|
126
|
-
|
|
123
|
+
test("Reverts all taken tokens when revert is called", async (done) => {
|
|
124
|
+
let limiterProcessor = await limiterWithMockService();
|
|
125
|
+
limiterProcessor
|
|
127
126
|
.transfer("a", "b", 5)
|
|
128
127
|
.then((result) => {
|
|
129
128
|
expect(result).toMatchObject({ conformant: true });
|
|
130
|
-
expect(
|
|
129
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(-5);
|
|
131
130
|
})
|
|
132
|
-
.then(() =>
|
|
131
|
+
.then(() => limiterProcessor.revert())
|
|
133
132
|
.then(() => {
|
|
134
|
-
expect(
|
|
133
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
135
134
|
done();
|
|
136
135
|
});
|
|
137
136
|
});
|
|
138
137
|
|
|
139
|
-
test("Reverts all given tokens when revert is called", (done) => {
|
|
140
|
-
let
|
|
141
|
-
|
|
138
|
+
test("Reverts all given tokens when revert is called", async (done) => {
|
|
139
|
+
let limiterProcessor = await limiterWithMockService();
|
|
140
|
+
limiterProcessor
|
|
142
141
|
.transfer("a", "b", -5)
|
|
143
142
|
.then((result) => {
|
|
144
143
|
expect(result).toMatchObject({});
|
|
145
|
-
expect(
|
|
144
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
146
145
|
})
|
|
147
|
-
.then(() =>
|
|
146
|
+
.then(() => limiterProcessor.revert())
|
|
148
147
|
.then(() => {
|
|
149
|
-
expect(
|
|
148
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
150
149
|
done();
|
|
151
150
|
});
|
|
152
151
|
});
|
|
153
152
|
|
|
154
|
-
test("Reverts a series of actions when revert is called", (done) => {
|
|
155
|
-
let
|
|
156
|
-
|
|
153
|
+
test("Reverts a series of actions when revert is called", async (done) => {
|
|
154
|
+
let limiterProcessor = await limiterWithMockService();
|
|
155
|
+
limiterProcessor
|
|
157
156
|
.transfer("a", "b", -5)
|
|
158
157
|
.then((result) => {
|
|
159
158
|
expect(result).toMatchObject({});
|
|
160
|
-
expect(
|
|
159
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
161
160
|
})
|
|
162
|
-
.then(() =>
|
|
161
|
+
.then(() => limiterProcessor.transfer("a", "b", 2))
|
|
163
162
|
.then((result) => {
|
|
164
163
|
expect(result).toMatchObject({ conformant: true });
|
|
165
|
-
expect(
|
|
164
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(3);
|
|
166
165
|
})
|
|
167
|
-
.then(() =>
|
|
166
|
+
.then(() => limiterProcessor.revert())
|
|
168
167
|
.then(() => {
|
|
169
|
-
expect(
|
|
168
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
170
169
|
done();
|
|
171
170
|
});
|
|
172
171
|
});
|
|
173
172
|
|
|
174
|
-
test("Properly executes a transferAll()", (done) => {
|
|
175
|
-
let
|
|
176
|
-
|
|
173
|
+
test("Properly executes a transferAll()", async (done) => {
|
|
174
|
+
let limiterProcessor = await limiterWithMockService();
|
|
175
|
+
limiterProcessor
|
|
177
176
|
.transferAll([
|
|
178
177
|
["a", "b", -5],
|
|
179
178
|
["a", "b", 2],
|
|
180
179
|
])
|
|
181
180
|
.then((result) => {
|
|
182
181
|
expect(result).toMatchObject([{}, { conformant: true }]);
|
|
183
|
-
expect(
|
|
182
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(3);
|
|
184
183
|
})
|
|
185
|
-
.then(() =>
|
|
184
|
+
.then(() => limiterProcessor.revert())
|
|
186
185
|
.then(() => {
|
|
187
|
-
expect(
|
|
186
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
188
187
|
done();
|
|
189
188
|
});
|
|
190
189
|
});
|
|
191
190
|
|
|
192
|
-
test("Errors from the underlying service are propagated (put)", () => {
|
|
193
|
-
let
|
|
194
|
-
let endsInFailure =
|
|
191
|
+
test("Errors from the underlying service are propagated (put)", async () => {
|
|
192
|
+
let limiterProcessor = await limiterWithMockService((succeeds = false));
|
|
193
|
+
let endsInFailure = limiterProcessor.transfer("a", "b", -5);
|
|
195
194
|
return expect(endsInFailure).rejects.toThrow(PUT_FAILED);
|
|
196
195
|
});
|
|
197
196
|
|
|
198
|
-
test("Errors from the underlying service are propagated (take)", () => {
|
|
199
|
-
let
|
|
200
|
-
let endsInFailure =
|
|
197
|
+
test("Errors from the underlying service are propagated (take)", async () => {
|
|
198
|
+
let limiterProcessor = await limiterWithMockService((succeeds = false));
|
|
199
|
+
let endsInFailure = limiterProcessor.transfer("a", "b", 5);
|
|
201
200
|
return expect(endsInFailure).rejects.toThrow(TAKE_FAILED);
|
|
202
201
|
});
|
|
203
202
|
|
|
204
|
-
test("Non-conforming response results in an error", () => {
|
|
205
|
-
let
|
|
206
|
-
let endsInFailure =
|
|
203
|
+
test("Non-conforming response results in an error", async () => {
|
|
204
|
+
let limiterProcessor = await limiterWithMockService((succeeds = true), (conforms = false));
|
|
205
|
+
let endsInFailure = limiterProcessor.transfer("a", "b", 5);
|
|
207
206
|
return expect(endsInFailure).rejects.toThrow("Non Conformant");
|
|
208
207
|
});
|
|
209
208
|
|
|
210
|
-
test("An operation that fails is not logged", (done) => {
|
|
211
|
-
let
|
|
212
|
-
|
|
209
|
+
test("An operation that fails is not logged", async (done) => {
|
|
210
|
+
let limiterProcessor = await limiterWithMockService();
|
|
211
|
+
limiterProcessor
|
|
213
212
|
.transfer("emailRate", "b", -5)
|
|
214
213
|
.then((result) => {
|
|
215
214
|
expect(result).toBe(null);
|
|
216
|
-
expect(
|
|
217
|
-
|
|
215
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
216
|
+
limiterProcessor.succeeds = false; // somebody is playing games
|
|
218
217
|
})
|
|
219
|
-
.then(() =>
|
|
218
|
+
.then(() => limiterProcessor.transfer("emailRate", "b", 2))
|
|
220
219
|
.catch(() => "failed uniquely!") // do nothing!
|
|
221
220
|
.then((result) => {
|
|
222
221
|
expect(result).toBe("failed uniquely!");
|
|
223
|
-
expect(
|
|
224
|
-
|
|
222
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
223
|
+
limiterProcessor.succeeds = true; // for real this time
|
|
225
224
|
})
|
|
226
|
-
.then(() =>
|
|
225
|
+
.then(() => limiterProcessor.revert())
|
|
227
226
|
.then(() => {
|
|
228
|
-
expect(
|
|
227
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
229
228
|
done();
|
|
230
229
|
});
|
|
231
230
|
});
|
|
232
231
|
|
|
233
|
-
test("Properly handles spamming revert() calls", (done) => {
|
|
234
|
-
let
|
|
235
|
-
|
|
232
|
+
test("Properly handles spamming revert() calls", async (done) => {
|
|
233
|
+
let limiterProcessor = await limiterWithMockService();
|
|
234
|
+
limiterProcessor
|
|
236
235
|
.transfer("a", "b", -5)
|
|
237
236
|
.then((result) => {
|
|
238
237
|
expect(result).toMatchObject({});
|
|
239
|
-
expect(
|
|
238
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
|
|
240
239
|
})
|
|
241
|
-
.then(() =>
|
|
240
|
+
.then(() => limiterProcessor.transfer("a", "b", 2))
|
|
242
241
|
.then((result) => {
|
|
243
242
|
expect(result).toMatchObject({ conformant: true });
|
|
244
|
-
expect(
|
|
243
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(3);
|
|
245
244
|
})
|
|
246
245
|
.then(() =>
|
|
247
246
|
Promise.all([
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
247
|
+
limiterProcessor.revert(),
|
|
248
|
+
limiterProcessor.revert(),
|
|
249
|
+
limiterProcessor.revert(),
|
|
250
|
+
limiterProcessor.revert(),
|
|
251
|
+
limiterProcessor.revert(),
|
|
252
|
+
limiterProcessor.revert(),
|
|
253
|
+
limiterProcessor.revert(),
|
|
254
|
+
limiterProcessor.revert(),
|
|
255
|
+
limiterProcessor.revert(),
|
|
256
|
+
limiterProcessor.revert(),
|
|
257
|
+
limiterProcessor.revert(),
|
|
258
|
+
limiterProcessor.revert(),
|
|
259
|
+
limiterProcessor.revert(),
|
|
260
|
+
limiterProcessor.revert(),
|
|
261
|
+
limiterProcessor.revert(),
|
|
262
|
+
limiterProcessor.revert(),
|
|
264
263
|
])
|
|
265
264
|
)
|
|
266
265
|
.then(() => {
|
|
267
|
-
expect(
|
|
266
|
+
expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
|
|
268
267
|
done();
|
|
269
268
|
});
|
|
270
269
|
});
|
|
@@ -6,12 +6,13 @@ async function performTestWithTestPerMinute() {
|
|
|
6
6
|
limitdUrl: "localhost:6379",
|
|
7
7
|
console: console,
|
|
8
8
|
});
|
|
9
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
9
10
|
// take 2 # Conformant - Remaining: 1
|
|
10
|
-
const result1 = await
|
|
11
|
+
const result1 = await limiterProcessor.transfer("testPerMinute", "key", 2);
|
|
11
12
|
console.log("First Turn Take Result", result1);
|
|
12
13
|
|
|
13
14
|
//Now Conformant - Remaining: 1
|
|
14
|
-
const result2 = await
|
|
15
|
+
const result2 = await limiterProcessor
|
|
15
16
|
.transfer("testPerMinute", "key", 2)
|
|
16
17
|
.catch((err) => {
|
|
17
18
|
console.log("Second Turn Take Error", err.message);
|
|
@@ -19,11 +20,11 @@ async function performTestWithTestPerMinute() {
|
|
|
19
20
|
console.log("Second Turn Take Result", result2);
|
|
20
21
|
|
|
21
22
|
// Put 1
|
|
22
|
-
const result3 = await
|
|
23
|
+
const result3 = await limiterProcessor.transfer("testPerMinute", "key", -1);
|
|
23
24
|
console.log("Third Turn PUT Result", result3);
|
|
24
25
|
|
|
25
26
|
//Now Conformant - Remaining: 2
|
|
26
|
-
const result4 = await
|
|
27
|
+
const result4 = await limiterProcessor.transfer("testPerMinute", "key", 2);
|
|
27
28
|
console.log("Fourth Turn Take Result", result4);
|
|
28
29
|
process.exit(1);
|
|
29
30
|
}
|
package/tests/sanityCheck.js
CHANGED
|
@@ -2,31 +2,36 @@
|
|
|
2
2
|
|
|
3
3
|
var Limiter = require("../limiter");
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
]
|
|
31
|
-
|
|
32
|
-
|
|
5
|
+
async function sanityCheck(){
|
|
6
|
+
const buckets = {
|
|
7
|
+
emails: { size: 10 },
|
|
8
|
+
emailRate: { size: 10, per_hour: 10 },
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
var limiter = new Limiter({
|
|
12
|
+
limitdUrl: "localhost:6379",
|
|
13
|
+
buckets,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const limiterProcessor = await limiter.getLimiterProcessor(console);
|
|
17
|
+
|
|
18
|
+
var callback = function (err) {
|
|
19
|
+
if (err) {
|
|
20
|
+
console.log(err);
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
process.exit(0);
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
var withdrawls = [
|
|
28
|
+
["emails", process.argv[2], -parseInt(process.argv[3])],
|
|
29
|
+
["emailRate", process.argv[2], -parseInt(process.argv[3])],
|
|
30
|
+
["emails", process.argv[2], parseInt(process.argv[3])],
|
|
31
|
+
["emailRate", process.argv[2], parseInt(process.argv[3])],
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
limiterProcessor.transferAll(withdrawls).then(() => callback(), callback);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
sanityCheck();
|