@withjoy/limiter 0.1.1 → 0.1.2

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 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._operationList = [];
48
- this._limitdRedis = this.connect();
46
+ this._limitdRedisConnection = this.connect();
49
47
  }
50
48
 
51
49
  /*
@@ -67,10 +65,35 @@ class Limiter {
67
65
  keyPrefix,
68
66
  });
69
67
  }
70
- this._limitdRedis = connection;
71
68
  return connection;
72
69
  }
73
70
 
71
+ getLimiterProcessor(console) {
72
+ return new LimiterProcessor(console);
73
+ }
74
+
75
+ close() {
76
+ return new Promise((resolve, reject) => {
77
+ this._limitdRedisConnection.close((err, resp) => {
78
+ if (err) {
79
+ this._console.error(err);
80
+ return reject(err);
81
+ }
82
+ console.log("Connection closed");
83
+ resolve(resp);
84
+ });
85
+ });
86
+ }
87
+ }
88
+
89
+ class LimiterProcessor {
90
+
91
+ constructor(console) {
92
+ this._console = console;
93
+ this._operationList = [];
94
+ this._limitdRedis = connection;
95
+ }
96
+
74
97
  /*
75
98
  Go through the log of things we did and do the opposite
76
99
  */
@@ -97,18 +120,6 @@ class Limiter {
97
120
  this._operationList.push(op);
98
121
  }
99
122
 
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
123
  // promise wrapper for limitd lib put
113
124
  _put(type, id, amount) {
114
125
  return new Promise((resolve, reject) =>
@@ -173,12 +184,12 @@ Limiter.pickDefaultBuckets = function pickDefaultBuckets(keyArray) {
173
184
  const buckets = {};
174
185
  for (const key of keyArray) {
175
186
  const bucket = defaultBuckets[key];
176
- if (! bucket) {
187
+ if (!bucket) {
177
188
  throw new Error(`Limiter.pickDefaultBuckets: no such bucket; "${key}"`);
178
189
  }
179
190
  buckets[key] = defaultBuckets[key];
180
191
  }
181
192
  return buckets;
182
- }
193
+ };
183
194
 
184
195
  module.exports = Limiter;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@withjoy/limiter",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Api Rate limiter",
5
5
  "main": "limiter.js",
6
6
  "scripts": {
@@ -19,12 +19,11 @@ const TEST_BUCKETS = {
19
19
  const limiterWithMockService = (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
- limiter._limitdRedis = new (class MockLimitd {
25
+ const limiterProcessor = 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 limiter;
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 = limiter.getLimiterProcessor(console);
66
65
  // take 2 # Conformant - Remaining: 1
67
- const result1 = await limiter.transfer("test", "test-key", 2);
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(limiter.transfer("test", "test-key", 2)).rejects.toThrow(
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 limiter.transfer("test", "test-key", -1);
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 limiter.transfer("test", "test-key", 2);
85
+ const result4 = await limiterProcessor.transfer("test", "test-key", 2);
87
86
  expect(result4).toMatchObject({
88
87
  conformant: true,
89
88
  remaining: 0,
@@ -95,176 +94,176 @@ test("perfrom limitd-redis testing with test bucket", async (done) => {
95
94
  });
96
95
 
97
96
  test("Resolves to null if we aren't doing a real transfer", (done) => {
98
- let limiter = limiterWithMockService();
99
- limiter.transfer("a", "b", 0, null).then((result) => {
97
+ let limiterProcessor = limiterWithMockService();
98
+ limiterProcessor.transfer("a", "b", 0, null).then((result) => {
100
99
  expect(result).toBe(null);
101
- expect(limiter._limitdRedis._num_tokens()).toBe(0);
100
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
102
101
  done();
103
102
  });
104
103
  });
105
104
 
106
105
  test("Adds tokens if provided a negative token amount", (done) => {
107
- let limiter = limiterWithMockService();
108
- limiter.transfer("a", "b", -5).then((result) => {
106
+ let limiterProcessor = limiterWithMockService();
107
+ limiterProcessor.transfer("a", "b", -5).then((result) => {
109
108
  expect(result).toMatchObject({});
110
- expect(limiter._limitdRedis._num_tokens()).toBe(5);
109
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
111
110
  done();
112
111
  });
113
112
  });
114
113
 
115
114
  test("Removes tokens if provided a positive token amount", (done) => {
116
- let limiter = limiterWithMockService();
117
- limiter.transfer("a", "b", 5).then((result) => {
115
+ let limiterProcessor = limiterWithMockService();
116
+ limiterProcessor.transfer("a", "b", 5).then((result) => {
118
117
  expect(result).toMatchObject({ conformant: true });
119
- expect(limiter._limitdRedis._num_tokens()).toBe(-5);
118
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(-5);
120
119
  done();
121
120
  });
122
121
  });
123
122
 
124
123
  test("Reverts all taken tokens when revert is called", (done) => {
125
- let limiter = limiterWithMockService();
126
- limiter
124
+ let limiterProcessor = limiterWithMockService();
125
+ limiterProcessor
127
126
  .transfer("a", "b", 5)
128
127
  .then((result) => {
129
128
  expect(result).toMatchObject({ conformant: true });
130
- expect(limiter._limitdRedis._num_tokens()).toBe(-5);
129
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(-5);
131
130
  })
132
- .then(() => limiter.revert())
131
+ .then(() => limiterProcessor.revert())
133
132
  .then(() => {
134
- expect(limiter._limitdRedis._num_tokens()).toBe(0);
133
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
135
134
  done();
136
135
  });
137
136
  });
138
137
 
139
138
  test("Reverts all given tokens when revert is called", (done) => {
140
- let limiter = limiterWithMockService();
141
- limiter
139
+ let limiterProcessor = limiterWithMockService();
140
+ limiterProcessor
142
141
  .transfer("a", "b", -5)
143
142
  .then((result) => {
144
143
  expect(result).toMatchObject({});
145
- expect(limiter._limitdRedis._num_tokens()).toBe(5);
144
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
146
145
  })
147
- .then(() => limiter.revert())
146
+ .then(() => limiterProcessor.revert())
148
147
  .then(() => {
149
- expect(limiter._limitdRedis._num_tokens()).toBe(0);
148
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
150
149
  done();
151
150
  });
152
151
  });
153
152
 
154
153
  test("Reverts a series of actions when revert is called", (done) => {
155
- let limiter = limiterWithMockService();
156
- limiter
154
+ let limiterProcessor = limiterWithMockService();
155
+ limiterProcessor
157
156
  .transfer("a", "b", -5)
158
157
  .then((result) => {
159
158
  expect(result).toMatchObject({});
160
- expect(limiter._limitdRedis._num_tokens()).toBe(5);
159
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
161
160
  })
162
- .then(() => limiter.transfer("a", "b", 2))
161
+ .then(() => limiterProcessor.transfer("a", "b", 2))
163
162
  .then((result) => {
164
163
  expect(result).toMatchObject({ conformant: true });
165
- expect(limiter._limitdRedis._num_tokens()).toBe(3);
164
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(3);
166
165
  })
167
- .then(() => limiter.revert())
166
+ .then(() => limiterProcessor.revert())
168
167
  .then(() => {
169
- expect(limiter._limitdRedis._num_tokens()).toBe(0);
168
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
170
169
  done();
171
170
  });
172
171
  });
173
172
 
174
173
  test("Properly executes a transferAll()", (done) => {
175
- let limiter = limiterWithMockService();
176
- limiter
174
+ let limiterProcessor = 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(limiter._limitdRedis._num_tokens()).toBe(3);
182
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(3);
184
183
  })
185
- .then(() => limiter.revert())
184
+ .then(() => limiterProcessor.revert())
186
185
  .then(() => {
187
- expect(limiter._limitdRedis._num_tokens()).toBe(0);
186
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
188
187
  done();
189
188
  });
190
189
  });
191
190
 
192
191
  test("Errors from the underlying service are propagated (put)", () => {
193
- let limiter = limiterWithMockService((succeeds = false));
194
- let endsInFailure = limiter.transfer("a", "b", -5);
192
+ let limiterProcessor = 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
197
  test("Errors from the underlying service are propagated (take)", () => {
199
- let limiter = limiterWithMockService((succeeds = false));
200
- let endsInFailure = limiter.transfer("a", "b", 5);
198
+ let limiterProcessor = 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
203
  test("Non-conforming response results in an error", () => {
205
- let limiter = limiterWithMockService((succeeds = true), (conforms = false));
206
- let endsInFailure = limiter.transfer("a", "b", 5);
204
+ let limiterProcessor = 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
209
  test("An operation that fails is not logged", (done) => {
211
- let limiter = limiterWithMockService();
212
- limiter
210
+ let limiterProcessor = limiterWithMockService();
211
+ limiterProcessor
213
212
  .transfer("emailRate", "b", -5)
214
213
  .then((result) => {
215
214
  expect(result).toBe(null);
216
- expect(limiter._limitdRedis._num_tokens()).toBe(5);
217
- limiter.succeeds = false; // somebody is playing games
215
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
216
+ limiterProcessor.succeeds = false; // somebody is playing games
218
217
  })
219
- .then(() => limiter.transfer("emailRate", "b", 2))
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(limiter._limitdRedis._num_tokens()).toBe(5);
224
- limiter.succeeds = true; // for real this time
222
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
223
+ limiterProcessor.succeeds = true; // for real this time
225
224
  })
226
- .then(() => limiter.revert())
225
+ .then(() => limiterProcessor.revert())
227
226
  .then(() => {
228
- expect(limiter._limitdRedis._num_tokens()).toBe(0);
227
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(0);
229
228
  done();
230
229
  });
231
230
  });
232
231
 
233
232
  test("Properly handles spamming revert() calls", (done) => {
234
- let limiter = limiterWithMockService();
235
- limiter
233
+ let limiterProcessor = limiterWithMockService();
234
+ limiterProcessor
236
235
  .transfer("a", "b", -5)
237
236
  .then((result) => {
238
237
  expect(result).toMatchObject({});
239
- expect(limiter._limitdRedis._num_tokens()).toBe(5);
238
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(5);
240
239
  })
241
- .then(() => limiter.transfer("a", "b", 2))
240
+ .then(() => limiterProcessor.transfer("a", "b", 2))
242
241
  .then((result) => {
243
242
  expect(result).toMatchObject({ conformant: true });
244
- expect(limiter._limitdRedis._num_tokens()).toBe(3);
243
+ expect(limiterProcessor._limitdRedis._num_tokens()).toBe(3);
245
244
  })
246
245
  .then(() =>
247
246
  Promise.all([
248
- limiter.revert(),
249
- limiter.revert(),
250
- limiter.revert(),
251
- limiter.revert(),
252
- limiter.revert(),
253
- limiter.revert(),
254
- limiter.revert(),
255
- limiter.revert(),
256
- limiter.revert(),
257
- limiter.revert(),
258
- limiter.revert(),
259
- limiter.revert(),
260
- limiter.revert(),
261
- limiter.revert(),
262
- limiter.revert(),
263
- limiter.revert(),
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(limiter._limitdRedis._num_tokens()).toBe(0);
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 = limiter.getLimiterProcessor(console);
9
10
  // take 2 # Conformant - Remaining: 1
10
- const result1 = await limiter.transfer("testPerMinute", "key", 2);
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 limiter
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 limiter.transfer("testPerMinute", "key", -1);
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 limiter.transfer("testPerMinute", "key", 2);
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
  }
@@ -9,10 +9,11 @@ const buckets = {
9
9
 
10
10
  var limiter = new Limiter({
11
11
  limitdUrl: "localhost:6379",
12
- console: console,
13
12
  buckets,
14
13
  });
15
14
 
15
+ var limiterProcessor = limiter.getLimiterProcessor(console);
16
+
16
17
  var callback = function (err) {
17
18
  if (err) {
18
19
  console.log(err);
@@ -29,4 +30,4 @@ var withdrawls = [
29
30
  ["emailRate", process.argv[2], parseInt(process.argv[3])],
30
31
  ];
31
32
 
32
- limiter.transferAll(withdrawls).then(() => callback(), callback);
33
+ limiterProcessor.transferAll(withdrawls).then(() => callback(), callback);