lemon-core 3.1.1 → 3.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.
Files changed (83) hide show
  1. package/README.md +2 -1
  2. package/dist/controllers/dummy-controller.d.ts +1 -1
  3. package/dist/controllers/general-api-controller.d.ts +1 -1
  4. package/dist/controllers/general-api-controller.js.map +1 -1
  5. package/dist/controllers/general-controller.d.ts +1 -1
  6. package/dist/cores/core-services.d.ts +1 -2
  7. package/dist/cores/core-services.js +0 -25
  8. package/dist/cores/core-services.js.map +1 -1
  9. package/dist/cores/dynamo/dynamo-query-service.d.ts +1 -1
  10. package/dist/cores/dynamo/dynamo-scan-service.d.ts +1 -1
  11. package/dist/cores/dynamo/dynamo-service.d.ts +1 -1
  12. package/dist/cores/elastic/elastic6-query-service.d.ts +1 -1
  13. package/dist/cores/elastic/elastic6-service.d.ts +1 -1
  14. package/dist/cores/index.d.ts +1 -1
  15. package/dist/cores/index.js +1 -1
  16. package/dist/cores/index.js.map +1 -1
  17. package/dist/cores/lambda/lambda-cron-handler.d.ts +1 -1
  18. package/dist/cores/lambda/lambda-dynamo-stream-handler.d.ts +1 -1
  19. package/dist/cores/lambda/lambda-dynamo-stream-handler.js.map +1 -1
  20. package/dist/cores/lambda/lambda-handler.d.ts +2 -1
  21. package/dist/cores/lambda/lambda-handler.js.map +1 -1
  22. package/dist/cores/lambda/lambda-notification-handler.d.ts +1 -1
  23. package/dist/cores/lambda/lambda-sns-handler.d.ts +1 -1
  24. package/dist/cores/lambda/lambda-sqs-handler.d.ts +1 -1
  25. package/dist/cores/lambda/lambda-web-handler.d.ts +2 -2
  26. package/dist/cores/lambda/lambda-web-handler.js.map +1 -1
  27. package/dist/cores/protocol/protocol-service.d.ts +1 -1
  28. package/dist/cores/storage/model-manager.d.ts +2 -1
  29. package/dist/cores/storage/model-manager.js.map +1 -1
  30. package/dist/cores/storage/proxy-storage-service.d.ts +2 -71
  31. package/dist/cores/storage/proxy-storage-service.js +4 -7
  32. package/dist/cores/storage/proxy-storage-service.js.map +1 -1
  33. package/dist/cores/storage/storage-service.d.ts +5 -17
  34. package/dist/cores/storage/storage-service.js +3 -0
  35. package/dist/cores/storage/storage-service.js.map +1 -1
  36. package/dist/engine/engine.d.ts +1 -1
  37. package/dist/engine/engine.js.map +1 -1
  38. package/dist/extended/abstract-service.d.ts +8 -1
  39. package/dist/extended/abstract-service.js +13 -4
  40. package/dist/extended/abstract-service.js.map +1 -1
  41. package/package.json +3 -2
  42. package/dist/cores/api-service.d.ts +0 -239
  43. package/dist/cores/api-service.js +0 -674
  44. package/dist/cores/api-service.js.map +0 -1
  45. package/dist/cores/cache-service.d.ts +0 -424
  46. package/dist/cores/cache-service.js +0 -948
  47. package/dist/cores/cache-service.js.map +0 -1
  48. package/dist/cores/core-types.d.ts +0 -398
  49. package/dist/cores/core-types.js +0 -15
  50. package/dist/cores/core-types.js.map +0 -1
  51. package/dist/cores/dynamo-query-service.d.ts +0 -52
  52. package/dist/cores/dynamo-query-service.js +0 -127
  53. package/dist/cores/dynamo-query-service.js.map +0 -1
  54. package/dist/cores/dynamo-scan-service.d.ts +0 -70
  55. package/dist/cores/dynamo-scan-service.js +0 -164
  56. package/dist/cores/dynamo-scan-service.js.map +0 -1
  57. package/dist/cores/dynamo-service.d.ts +0 -192
  58. package/dist/cores/dynamo-service.js +0 -525
  59. package/dist/cores/dynamo-service.js.map +0 -1
  60. package/dist/cores/elastic6-query-service.d.ts +0 -104
  61. package/dist/cores/elastic6-query-service.js +0 -510
  62. package/dist/cores/elastic6-query-service.js.map +0 -1
  63. package/dist/cores/elastic6-service.d.ts +0 -273
  64. package/dist/cores/elastic6-service.js +0 -903
  65. package/dist/cores/elastic6-service.js.map +0 -1
  66. package/dist/cores/hangul-service.d.ts +0 -102
  67. package/dist/cores/hangul-service.js +0 -205
  68. package/dist/cores/hangul-service.js.map +0 -1
  69. package/dist/cores/http-storage-service.d.ts +0 -22
  70. package/dist/cores/http-storage-service.js +0 -129
  71. package/dist/cores/http-storage-service.js.map +0 -1
  72. package/dist/cores/model-manager.d.ts +0 -93
  73. package/dist/cores/model-manager.js +0 -192
  74. package/dist/cores/model-manager.js.map +0 -1
  75. package/dist/cores/proxy-storage-service.d.ts +0 -573
  76. package/dist/cores/proxy-storage-service.js +0 -913
  77. package/dist/cores/proxy-storage-service.js.map +0 -1
  78. package/dist/cores/redis-storage-service.d.ts +0 -183
  79. package/dist/cores/redis-storage-service.js +0 -391
  80. package/dist/cores/redis-storage-service.js.map +0 -1
  81. package/dist/cores/storage-service.d.ts +0 -170
  82. package/dist/cores/storage-service.js +0 -389
  83. package/dist/cores/storage-service.js.map +0 -1
@@ -1,948 +0,0 @@
1
- "use strict";
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
- Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.fromTTL = exports.toTTL = exports.sleep = exports.DummyCacheService = exports.CacheService = void 0;
16
- /**
17
- * `cache-services.ts`
18
- * - common service for remote cache
19
- *
20
- * @author Tim Hong <tim@lemoncloud.io>
21
- * @date 2020-12-02 initial version
22
- * @author Steve <steve@lemoncloud.io>
23
- * @date 2022-04-01 optimized for `AbstractProxy`
24
- *
25
- * @copyright (C) lemoncloud.io 2020 - All Rights Reserved.
26
- */
27
- const util_1 = require("util");
28
- const node_cache_1 = __importDefault(require("node-cache"));
29
- const memcached_1 = __importDefault(require("memcached"));
30
- const ioredis_1 = __importDefault(require("ioredis"));
31
- const engine_1 = require("../engine");
32
- const NS = engine_1.$U.NS('CCHS', 'green'); // NAMESPACE TO BE PRINTED.
33
- /**
34
- * class `CacheService`
35
- * - common service to provide cache
36
- */
37
- class CacheService {
38
- /**
39
- * Protected constructor -> use CacheService.create()
40
- *
41
- * @param backend cache backend object
42
- * @param options options to create.
43
- * @protected
44
- */
45
- constructor(backend, options) {
46
- const ns = (options === null || options === void 0 ? void 0 : options.ns) || '';
47
- (0, engine_1._inf)(NS, `! cache-service instantiated with [${backend.name}] backend. [ns=${ns}]`);
48
- this.backend = backend;
49
- this.ns = ns;
50
- this.maker = options === null || options === void 0 ? void 0 : options.maker;
51
- }
52
- /**
53
- * Factory method
54
- *
55
- * @param options (optional) cache options
56
- * @param maker (optional) custome cache-pkey generator.
57
- * @static
58
- */
59
- static create(options, maker) {
60
- const type = (options === null || options === void 0 ? void 0 : options.type) || 'redis';
61
- const endpoint = (options === null || options === void 0 ? void 0 : options.endpoint) || engine_1.$U.env(CacheService.ENV_CACHE_ENDPOINT);
62
- const ns = (options === null || options === void 0 ? void 0 : options.ns) || '';
63
- const defTimeout = engine_1.$U.N(options === null || options === void 0 ? void 0 : options.defTimeout, engine_1.$U.N(engine_1.$U.env(CacheService.ENV_CACHE_DEFAULT_TIMEOUT), CacheService.DEF_CACHE_DEFAULT_TIMEOUT));
64
- (0, engine_1._log)(NS, `constructing [${type}] cache ...`);
65
- (0, engine_1._log)(NS, ` > endpoint =`, endpoint);
66
- (0, engine_1._log)(NS, ` > ns =`, ns);
67
- (0, engine_1._log)(NS, ` > defTimeout =`, defTimeout);
68
- let backend;
69
- switch (type) {
70
- case 'memcached':
71
- backend = new MemcachedBackend(endpoint, defTimeout);
72
- break;
73
- case 'redis':
74
- backend = new RedisBackend(endpoint, defTimeout);
75
- break;
76
- default:
77
- throw new Error(`@type [${type}] is invalid - CacheService.create()`);
78
- }
79
- return new CacheService(backend, { ns, maker });
80
- }
81
- /**
82
- * Say hello
83
- */
84
- hello() {
85
- return `cache-service:${this.backend.name}:${this.ns}`;
86
- }
87
- /**
88
- * Close backend and connection
89
- */
90
- close() {
91
- return __awaiter(this, void 0, void 0, function* () {
92
- yield this.backend.close();
93
- });
94
- }
95
- /**
96
- * Check whether the key is cached
97
- *
98
- * @return true if the key is cached
99
- */
100
- exists(key) {
101
- return __awaiter(this, void 0, void 0, function* () {
102
- const namespacedKey = this.asNamespacedKey(key);
103
- const ret = yield this.backend.has(namespacedKey);
104
- (0, engine_1._log)(NS, `.exists ${namespacedKey} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
105
- return ret;
106
- });
107
- }
108
- /**
109
- * List all keys
110
- *
111
- * @return list of keys
112
- */
113
- keys() {
114
- return __awaiter(this, void 0, void 0, function* () {
115
- const namespacedKeys = yield this.backend.keys();
116
- const ret = namespacedKeys.reduce((keys, namespacedKey) => {
117
- const [ns, key] = namespacedKey.split(CacheService.NAMESPACE_DELIMITER);
118
- if (ns === this.ns)
119
- keys.push(key);
120
- return keys;
121
- }, []);
122
- (0, engine_1._log)(NS, `.keys / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
123
- return ret;
124
- });
125
- }
126
- /**
127
- * Store a key
128
- *
129
- * @param key
130
- * @param val
131
- * @param timeout (optional) TTL in seconds or Timeout object
132
- * @return true on success
133
- */
134
- set(key, val, timeout) {
135
- return __awaiter(this, void 0, void 0, function* () {
136
- if (!key)
137
- throw new Error(`@key (CacheKey) is required.`);
138
- if (val === undefined)
139
- throw new Error(`@val (CacheValue) cannot be undefined.`);
140
- const namespacedKey = this.asNamespacedKey(key);
141
- const ttl = timeout && toTTL(timeout);
142
- const ret = yield this.backend.set(namespacedKey, val, ttl);
143
- (0, engine_1._log)(NS, `.set ${namespacedKey} ${val} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
144
- return ret;
145
- });
146
- }
147
- /**
148
- * Store multiple keys
149
- *
150
- * @param entries
151
- * @return true on success
152
- */
153
- setMulti(entries) {
154
- return __awaiter(this, void 0, void 0, function* () {
155
- const param = entries.map(({ key, val, timeout }, idx) => {
156
- if (!key)
157
- throw new Error(`.key (CacheKey) is required (at @entries[${idx}]).`);
158
- if (val === undefined)
159
- throw new Error(`.val (CacheValue) cannot be undefined (at @entries[${idx}]).`);
160
- return {
161
- key: this.asNamespacedKey(key),
162
- val,
163
- ttl: timeout && toTTL(timeout),
164
- };
165
- });
166
- const ret = yield this.backend.mset(param);
167
- (0, engine_1._log)(NS, `.setMulti ${entries.map(entry => entry.key)} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
168
- return ret;
169
- });
170
- }
171
- /**
172
- * Retrieve a key
173
- *
174
- * @param key
175
- */
176
- get(key) {
177
- return __awaiter(this, void 0, void 0, function* () {
178
- if (!key)
179
- throw new Error(`@key (CacheKey) is required.`);
180
- const namespacedKey = this.asNamespacedKey(key);
181
- const ret = yield this.backend.get(namespacedKey);
182
- (0, engine_1._log)(NS, `.get ${namespacedKey} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
183
- return ret;
184
- });
185
- }
186
- /**
187
- * Get multiple keys
188
- *
189
- * @param keys
190
- */
191
- getMulti(keys) {
192
- return __awaiter(this, void 0, void 0, function* () {
193
- const namespacedKeys = keys.map((key, idx) => {
194
- if (!key)
195
- throw new Error(`@key (CacheKey) is required (at @keys[${idx}]).`);
196
- return this.asNamespacedKey(key);
197
- });
198
- const map = yield this.backend.mget(namespacedKeys);
199
- // Remove namespace prefix from keys
200
- const ret = Object.entries(map).reduce((newMap, [namespacedKey, val]) => {
201
- const key = namespacedKey.split(CacheService.NAMESPACE_DELIMITER)[1];
202
- newMap[key] = val;
203
- return newMap;
204
- }, {});
205
- (0, engine_1._log)(NS, `.getMulti ${namespacedKeys} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
206
- return ret;
207
- });
208
- }
209
- /**
210
- * Increment the integer value of a key
211
- *
212
- * @param key
213
- * @param inc number to increment
214
- */
215
- increment(key, inc) {
216
- return __awaiter(this, void 0, void 0, function* () {
217
- if (!key)
218
- throw new Error(`@key (CacheKey) is required.`);
219
- if (inc === undefined)
220
- throw new Error(`@inc (number) cannot be undefined.`);
221
- const namespacedKey = this.asNamespacedKey(key);
222
- const ret = yield this.backend.incr(namespacedKey, inc);
223
- (0, engine_1._log)(NS, `.increment ${namespacedKey} ${inc} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
224
- return ret;
225
- });
226
- }
227
- /**
228
- * same as increment()
229
- */
230
- inc(key, inc) {
231
- return this.increment(key, inc);
232
- }
233
- /**
234
- * Set the value of a key and return its old value
235
- */
236
- getAndSet(key, val) {
237
- return __awaiter(this, void 0, void 0, function* () {
238
- if (!key)
239
- throw new Error(`@key (CacheKey) is required.`);
240
- if (val === undefined)
241
- throw new Error(`@val (CacheValue) cannot be undefined.`);
242
- const namespacedKey = this.asNamespacedKey(key);
243
- let ret;
244
- if (this.backend.getset) {
245
- ret = yield this.backend.getset(namespacedKey, val);
246
- }
247
- else {
248
- ret = yield this.backend.get(namespacedKey);
249
- // Best effort to keep remaining TTL
250
- let ttl = yield this.backend.ttl(namespacedKey);
251
- if (ttl !== undefined) {
252
- ttl = Math.ceil(ttl / 1000);
253
- }
254
- if (!(yield this.backend.set(namespacedKey, val, ttl)))
255
- throw new Error(`getAndSet() failed`);
256
- }
257
- (0, engine_1._log)(NS, `.getAndSet ${namespacedKey} ${val} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
258
- return ret;
259
- });
260
- }
261
- /**
262
- * Get and delete the key
263
- *
264
- * @param key
265
- */
266
- getAndDelete(key) {
267
- return __awaiter(this, void 0, void 0, function* () {
268
- if (!key)
269
- throw new Error(`@key (CacheKey) is required.`);
270
- const namespacedKey = this.asNamespacedKey(key);
271
- let ret;
272
- if (this.backend.pop) {
273
- ret = yield this.backend.pop(namespacedKey);
274
- }
275
- else {
276
- ret = yield this.backend.get(namespacedKey);
277
- yield this.backend.del(namespacedKey);
278
- }
279
- (0, engine_1._log)(NS, `.getAndDelete ${namespacedKey} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
280
- return ret;
281
- });
282
- }
283
- /**
284
- * Delete a key
285
- *
286
- * @param key
287
- * @return true on success
288
- */
289
- delete(key) {
290
- return __awaiter(this, void 0, void 0, function* () {
291
- if (!key)
292
- throw new Error(`@key (CacheKey) is required.`);
293
- const namespacedKey = this.asNamespacedKey(key);
294
- const ret = yield this.backend.del(namespacedKey);
295
- (0, engine_1._log)(NS, `.delete ${namespacedKey} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
296
- return ret;
297
- });
298
- }
299
- /**
300
- * Delete multiple keys
301
- *
302
- * @param keys
303
- * @return number of deleted entries
304
- */
305
- deleteMulti(keys) {
306
- return __awaiter(this, void 0, void 0, function* () {
307
- const namespacedKeys = keys.map((key, idx) => {
308
- if (!key)
309
- throw new Error(`@key (CacheKey) is required (at @keys[${idx}]).`);
310
- return this.asNamespacedKey(key);
311
- });
312
- const promises = namespacedKeys.map(namespacedKey => this.backend.del(namespacedKey));
313
- const ret = yield Promise.all(promises);
314
- (0, engine_1._log)(NS, `.deleteMulti ${namespacedKeys} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
315
- return ret;
316
- });
317
- }
318
- /**
319
- * Set or update the timeout of a key
320
- *
321
- * @param key
322
- * @param timeout TTL in seconds or Timeout object
323
- * @return true on success
324
- */
325
- setTimeout(key, timeout) {
326
- return __awaiter(this, void 0, void 0, function* () {
327
- if (!key)
328
- throw new Error(`@key (CacheKey) is required.`);
329
- const namespacedKey = this.asNamespacedKey(key);
330
- const ret = yield this.backend.expire(namespacedKey, toTTL(timeout));
331
- (0, engine_1._log)(NS, `.setTimeout ${namespacedKey} ${timeout} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
332
- return ret;
333
- });
334
- }
335
- /**
336
- * Get remaining time to live in milliseconds
337
- *
338
- * @return
339
- * - number of milliseconds to expire
340
- * - undefined if the key does not exist
341
- * - 0 if the key has no timeout
342
- */
343
- getTimeout(key) {
344
- return __awaiter(this, void 0, void 0, function* () {
345
- if (!key)
346
- throw new Error(`@key (CacheKey) is required.`);
347
- const namespacedKey = this.asNamespacedKey(key);
348
- const ret = yield this.backend.ttl(namespacedKey);
349
- (0, engine_1._log)(NS, `.getTimeout ${namespacedKey} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
350
- return ret;
351
- });
352
- }
353
- /**
354
- * Remove the timeout from a key
355
- *
356
- * @param key
357
- */
358
- removeTimeout(key) {
359
- return __awaiter(this, void 0, void 0, function* () {
360
- if (!key)
361
- throw new Error(`@key (CacheKey) is required.`);
362
- const namespacedKey = this.asNamespacedKey(key);
363
- const ret = yield this.backend.expire(namespacedKey, 0);
364
- (0, engine_1._log)(NS, `.removeTimeout ${namespacedKey} / ret =`, typeof ret === 'string' ? ret : engine_1.$U.json(ret));
365
- return ret;
366
- });
367
- }
368
- /**
369
- * Get namespace prefixed cache key
370
- *
371
- * @param key
372
- * @protected
373
- */
374
- asNamespacedKey(key) {
375
- const [ns, delim] = [this.ns, CacheService.NAMESPACE_DELIMITER];
376
- if (this.maker)
377
- return this.maker(ns, delim, key);
378
- return `${ns}${delim}${key}`;
379
- }
380
- }
381
- exports.CacheService = CacheService;
382
- /**
383
- * Environment variable name for cache server endpoint
384
- * @static
385
- */
386
- CacheService.ENV_CACHE_ENDPOINT = 'CACHE_ENDPOINT';
387
- /**
388
- * Environment variable name for default cache timeout
389
- * @static
390
- */
391
- CacheService.ENV_CACHE_DEFAULT_TIMEOUT = 'CACHE_DEFAULT_TIMEOUT';
392
- /**
393
- * Default cache timeout
394
- * @static
395
- */
396
- CacheService.DEF_CACHE_DEFAULT_TIMEOUT = 24 * 60 * 60; // 1-day
397
- /**
398
- * Namespace delimiter
399
- * @private
400
- * @static
401
- */
402
- CacheService.NAMESPACE_DELIMITER = '::';
403
- /**
404
- * class `DummyCacheService`: use 'node-cache' library
405
- */
406
- class DummyCacheService extends CacheService {
407
- /**
408
- * Factory method
409
- *
410
- * @param options (optional) cache options
411
- * @static
412
- */
413
- static create(options) {
414
- const ns = (options === null || options === void 0 ? void 0 : options.ns) || '';
415
- const defTimeout = engine_1.$U.N(options === null || options === void 0 ? void 0 : options.defTimeout, engine_1.$U.N(engine_1.$U.env(CacheService.ENV_CACHE_DEFAULT_TIMEOUT), CacheService.DEF_CACHE_DEFAULT_TIMEOUT));
416
- (0, engine_1._log)(NS, `constructing dummy cache ...`);
417
- // NOTE: Use singleton backend instance
418
- // because node-cache is volatile and client instance does not share keys with other instance
419
- if (!DummyCacheService.backend)
420
- DummyCacheService.backend = new NodeCacheBackend(defTimeout);
421
- return new DummyCacheService(DummyCacheService.backend, { ns });
422
- }
423
- /**
424
- * Say hello
425
- */
426
- hello() {
427
- return `dummy-${super.hello()}`;
428
- }
429
- }
430
- exports.DummyCacheService = DummyCacheService;
431
- /**
432
- * function `sleep`
433
- * @param ms duration in milliseconds
434
- */
435
- function sleep(ms) {
436
- return __awaiter(this, void 0, void 0, function* () {
437
- return new Promise(resolve => setTimeout(resolve, ms));
438
- });
439
- }
440
- exports.sleep = sleep;
441
- /**
442
- * Get TTL from timeout
443
- * @param timeout timeout in seconds or Timeout object
444
- * @return remaining time to live in seconds
445
- */
446
- function toTTL(timeout) {
447
- switch (typeof timeout) {
448
- case 'number':
449
- return timeout;
450
- case 'object':
451
- if (!timeout)
452
- return 0;
453
- const { expireIn, expireAt } = timeout;
454
- if (typeof expireIn === 'number')
455
- return expireIn;
456
- if (typeof expireAt === 'number') {
457
- const msTTL = timeout.expireAt - Date.now();
458
- return Math.ceil(msTTL / 1000);
459
- }
460
- break;
461
- }
462
- throw new Error(`@timeout (number | Timeout) is invalid.`);
463
- }
464
- exports.toTTL = toTTL;
465
- /**
466
- * Get timestamp of expiration from TTL
467
- * @param ttl remaining time to live in seconds
468
- * @return timestamp in milliseconds since epoch
469
- */
470
- function fromTTL(ttl) {
471
- return ttl > 0 ? Date.now() + ttl * 1000 : 0;
472
- }
473
- exports.fromTTL = fromTTL;
474
- /** ********************************************************************************************************************
475
- * Internal Classes
476
- ** ********************************************************************************************************************/
477
- /**
478
- * class `NodeCacheBackend`: use 'node-cache' library
479
- * @internal
480
- */
481
- class NodeCacheBackend {
482
- /**
483
- * Public constructor
484
- */
485
- constructor(defTTL = 0) {
486
- /**
487
- * backend type
488
- */
489
- this.name = 'node-cache';
490
- this.cache = new node_cache_1.default({ stdTTL: defTTL });
491
- }
492
- /**
493
- * CacheBackend.set implementation
494
- */
495
- set(key, val, ttl) {
496
- return __awaiter(this, void 0, void 0, function* () {
497
- return this.cache.set(key, val, ttl);
498
- });
499
- }
500
- /**
501
- * CacheBackend.get implementation
502
- */
503
- get(key) {
504
- return __awaiter(this, void 0, void 0, function* () {
505
- return this.cache.get(key);
506
- });
507
- }
508
- /**
509
- * CacheBackend.mset implementation
510
- */
511
- mset(entries) {
512
- return __awaiter(this, void 0, void 0, function* () {
513
- return this.cache.mset(entries);
514
- });
515
- }
516
- /**
517
- * CacheBackend.mget implementation
518
- */
519
- mget(keys) {
520
- return __awaiter(this, void 0, void 0, function* () {
521
- return this.cache.mget(keys);
522
- });
523
- }
524
- /**
525
- * CacheBackend.pop implementation
526
- */
527
- pop(key) {
528
- return __awaiter(this, void 0, void 0, function* () {
529
- return this.cache.take(key);
530
- });
531
- }
532
- /**
533
- * CacheBackend.incr implementation
534
- */
535
- incr(key, increment) {
536
- return __awaiter(this, void 0, void 0, function* () {
537
- const org = this.cache.get(key);
538
- if (typeof org !== 'number')
539
- throw new Error(`@key [${key}] does not hold a number value.`);
540
- const newVal = org + increment;
541
- this.cache.set(key, newVal);
542
- return newVal;
543
- });
544
- }
545
- /**
546
- * CacheBackend.keys implementation
547
- */
548
- keys() {
549
- return __awaiter(this, void 0, void 0, function* () {
550
- return this.cache.keys();
551
- });
552
- }
553
- /**
554
- * CacheBackend.has implementation
555
- */
556
- has(key) {
557
- return __awaiter(this, void 0, void 0, function* () {
558
- return this.cache.has(key);
559
- });
560
- }
561
- /**
562
- * CacheBackend.del implementation
563
- */
564
- del(key) {
565
- return __awaiter(this, void 0, void 0, function* () {
566
- return this.cache.del(key) === 1;
567
- });
568
- }
569
- /**
570
- * CacheBackend.expire implementation
571
- */
572
- expire(key, ttl) {
573
- return __awaiter(this, void 0, void 0, function* () {
574
- return this.cache.ttl(key, ttl);
575
- });
576
- }
577
- /**
578
- * CacheBackend.ttl implementation
579
- */
580
- ttl(key) {
581
- return __awaiter(this, void 0, void 0, function* () {
582
- const ts = this.cache.getTtl(key); // Timestamp in milliseconds
583
- return ts && ts - Date.now();
584
- });
585
- }
586
- /**
587
- * CacheBackend.close implementation
588
- */
589
- close() {
590
- return __awaiter(this, void 0, void 0, function* () {
591
- this.cache.close();
592
- });
593
- }
594
- }
595
- /**
596
- * class `MemcachedBackend`
597
- * @internal
598
- */
599
- class MemcachedBackend {
600
- /**
601
- * Public constructor
602
- */
603
- constructor(endpoint, defTTL = 0) {
604
- /**
605
- * backend type
606
- */
607
- this.name = 'memcached';
608
- const memcached = new memcached_1.default(endpoint || 'localhost:11211');
609
- // Build promisified API map
610
- this.api = {
611
- get: (0, util_1.promisify)(memcached.get.bind(memcached)),
612
- gets: (0, util_1.promisify)(memcached.gets.bind(memcached)),
613
- getMulti: (0, util_1.promisify)(memcached.getMulti.bind(memcached)),
614
- set: (0, util_1.promisify)(memcached.set.bind(memcached)),
615
- cas: (0, util_1.promisify)(memcached.cas.bind(memcached)),
616
- del: (0, util_1.promisify)(memcached.del.bind(memcached)),
617
- items: (0, util_1.promisify)(memcached.items.bind(memcached)),
618
- cachedump: (server, slabid, number) => {
619
- return new Promise((resolve, reject) => {
620
- memcached.cachedump(server, slabid, number, (err, cachedump) => {
621
- if (err)
622
- return reject(err);
623
- if (!cachedump)
624
- return resolve([]);
625
- // Deep-copy를 안하면 데이터가 없어지는 이슈가 있음
626
- resolve(Array.isArray(cachedump) ? [...cachedump] : [cachedump]);
627
- });
628
- });
629
- },
630
- end: memcached.end.bind(memcached),
631
- };
632
- // default TTL
633
- this.defTTL = defTTL;
634
- }
635
- /**
636
- * CacheBackend.set implementation
637
- */
638
- set(key, val, ttl = this.defTTL) {
639
- return __awaiter(this, void 0, void 0, function* () {
640
- const entry = { val, exp: fromTTL(ttl) };
641
- (0, engine_1._log)(NS, `[${this.name}-backend] storing to key [${key}] =`, engine_1.$U.json(entry));
642
- return yield this.api.set(key, entry, ttl);
643
- });
644
- }
645
- /**
646
- * CacheBackend.get implementation
647
- */
648
- get(key) {
649
- return __awaiter(this, void 0, void 0, function* () {
650
- const entry = yield this.api.get(key);
651
- (0, engine_1._log)(NS, `[${this.name}-backend] entry fetched =`, engine_1.$U.json(entry));
652
- return entry && entry.val;
653
- });
654
- }
655
- /**
656
- * CacheBackend.mset implementation
657
- */
658
- mset(entries) {
659
- return __awaiter(this, void 0, void 0, function* () {
660
- (0, engine_1._log)(NS, `[${this.name}-backend] storing multiple keys ...`);
661
- const promises = entries.map(({ key, val, ttl = this.defTTL }, idx) => {
662
- const entry = { val, exp: fromTTL(ttl) };
663
- (0, engine_1._log)(NS, ` ${idx}) key [${key}] =`, engine_1.$U.json(entry));
664
- return this.api.set(key, entry, ttl);
665
- });
666
- const results = yield Promise.all(promises);
667
- return results.every(result => result === true);
668
- });
669
- }
670
- /**
671
- * CacheBackend.mget implementation
672
- */
673
- mget(keys) {
674
- return __awaiter(this, void 0, void 0, function* () {
675
- const map = yield this.api.getMulti(keys);
676
- (0, engine_1._log)(NS, `[${this.name}-backend] entry map fetched =`, engine_1.$U.json(map));
677
- Object.keys(map).forEach(key => {
678
- const entry = map[key];
679
- map[key] = entry.val;
680
- });
681
- return map;
682
- });
683
- }
684
- /**
685
- * CacheBackend.incr implementation
686
- */
687
- incr(key, increment) {
688
- return __awaiter(this, void 0, void 0, function* () {
689
- // NOTE:
690
- // Memcached는 음수에 대한 incr/decr를 지원하지 않으며 0 미만으로 decr 되지 않는다.
691
- // 이런 이유로 sets & cas 조합을 이용해 직접 구현함
692
- (0, engine_1._log)(NS, `[${this.name}-backend] incrementing (${increment}) to key [${key}] ...`);
693
- // Use get/check-and-save + retry strategy for consistency
694
- for (let retry = 0; retry < 5; yield sleep(10), retry++) {
695
- const result = yield this.api.gets(key); // Get entry w/ CAS id
696
- if (result === undefined) {
697
- // Initialize to increment value if the key does not exist
698
- if (!(yield this.set(key, increment, 0)))
699
- break;
700
- return increment;
701
- }
702
- else {
703
- const { [key]: oldEntry, cas } = result;
704
- if (typeof oldEntry.val !== 'number')
705
- throw new Error(`.key [${key}] has non-numeric value.`);
706
- // Preserve remaining lifetime w/ best effort strategy, not accurate
707
- const now = Date.now();
708
- const ttl = oldEntry.exp && Math.round((oldEntry.exp - now) / 1000);
709
- const entry = {
710
- val: oldEntry.val + increment,
711
- exp: ttl && now + ttl * 1000,
712
- };
713
- if (yield this.api.cas(key, entry, cas, ttl))
714
- return entry.val;
715
- }
716
- }
717
- throw new Error(`[memcached] failed to increment key [${key}].`);
718
- });
719
- }
720
- /**
721
- * CacheBackend.keys implementation
722
- */
723
- keys() {
724
- return __awaiter(this, void 0, void 0, function* () {
725
- // NOTE:
726
- // memcached는 원래 keys 기능을 지원하지 않으며
727
- // 아래와 같이 cachedump를 사용하여 가능하지만 set한 key가 dump 될 때 까지 상당한 시간이 소요되는 것으로 보인다.
728
- // 따라서 이 operation의 결과를 신뢰하지 않도록 한다.
729
- const item = (yield this.api.items())[0];
730
- if (!item || Object.keys(item).length === 0)
731
- return [];
732
- const [server, slabid] = [item.server, Number(Object.keys(item)[0])];
733
- const number = item[slabid].number;
734
- const cachedump = yield this.api.cachedump(server, slabid, number);
735
- return cachedump.map(({ key }) => key);
736
- });
737
- }
738
- /**
739
- * CacheBackend.has implementation
740
- */
741
- has(key) {
742
- return __awaiter(this, void 0, void 0, function* () {
743
- return (yield this.api.get(key)) !== undefined;
744
- });
745
- }
746
- /**
747
- * CacheBackend.del implementation
748
- */
749
- del(key) {
750
- return __awaiter(this, void 0, void 0, function* () {
751
- return yield this.api.del(key);
752
- });
753
- }
754
- /**
755
- * CacheBackend.expire implementation
756
- */
757
- expire(key, ttl) {
758
- return __awaiter(this, void 0, void 0, function* () {
759
- let saved = false;
760
- for (let retry = 0; !saved && retry < 5; yield sleep(10), retry++) {
761
- const result = yield this.api.gets(key); // Get entry w/ CAS id
762
- if (result === undefined)
763
- break; // If key does not exist or already expired
764
- // Refresh timeout
765
- const { [key]: oldEntry, cas } = result;
766
- const newEntry = {
767
- val: oldEntry.val,
768
- exp: ttl && Date.now() + ttl * 1000,
769
- };
770
- saved = yield this.api.cas(key, newEntry, cas, ttl);
771
- }
772
- return saved;
773
- });
774
- }
775
- /**
776
- * CacheBackend.ttl implementation
777
- */
778
- ttl(key) {
779
- return __awaiter(this, void 0, void 0, function* () {
780
- const entry = yield this.api.get(key); // undefined if key does not exist
781
- return (entry === null || entry === void 0 ? void 0 : entry.exp) && entry.exp - Date.now();
782
- });
783
- }
784
- /**
785
- * CacheBackend.close implementation
786
- */
787
- close() {
788
- return __awaiter(this, void 0, void 0, function* () {
789
- this.api.end();
790
- });
791
- }
792
- }
793
- /**
794
- * class `RedisBackend`
795
- * @internal
796
- */
797
- class RedisBackend {
798
- /**
799
- * Public constructor
800
- */
801
- constructor(endpoint, defTTL = 0) {
802
- /**
803
- * backend type
804
- */
805
- this.name = 'redis';
806
- this.redis = new ioredis_1.default(endpoint || 'localhost:6379');
807
- this.defTTL = defTTL;
808
- }
809
- /**
810
- * CacheBackend.set implementation
811
- */
812
- set(key, val, ttl = this.defTTL) {
813
- return __awaiter(this, void 0, void 0, function* () {
814
- const data = JSON.stringify(val); // Serialize
815
- ttl > 0 ? yield this.redis.set(key, data, 'EX', ttl) : yield this.redis.set(key, data);
816
- return true; // 'set' command always return OK
817
- });
818
- }
819
- /**
820
- * CacheBackend.get implementation
821
- */
822
- get(key) {
823
- return __awaiter(this, void 0, void 0, function* () {
824
- const data = yield this.redis.get(key);
825
- if (data !== null)
826
- return JSON.parse(data); // Deserialize
827
- });
828
- }
829
- /**
830
- * CacheBackend.mset implementation
831
- */
832
- mset(entries) {
833
- return __awaiter(this, void 0, void 0, function* () {
834
- // Create transaction pipeline
835
- // -> MSET command를 사용할 수도 있으나 ttl 지정이 불가능하여 pipeline으로 구현함
836
- const pipeline = entries.reduce((pipeline, { key, val, ttl = this.defTTL }) => {
837
- const data = JSON.stringify(val); // Serialize
838
- return ttl > 0 ? pipeline.set(key, data, 'EX', ttl) : pipeline.set(key, data);
839
- }, this.redis.multi());
840
- // Execute transaction
841
- yield pipeline.exec(); // Always OK
842
- return true;
843
- });
844
- }
845
- /**
846
- * CacheBackend.mget implementation
847
- */
848
- mget(keys) {
849
- return __awaiter(this, void 0, void 0, function* () {
850
- const list = yield this.redis.mget(keys);
851
- // Deserialize and map array into object
852
- return list.reduce((map, data, idx) => {
853
- if (data !== null) {
854
- const key = keys[idx];
855
- map[key] = JSON.parse(data); // Deserialize
856
- }
857
- return map;
858
- }, {});
859
- });
860
- }
861
- /**
862
- * CacheBackend.getset implementation
863
- */
864
- getset(key, val) {
865
- return __awaiter(this, void 0, void 0, function* () {
866
- const newData = JSON.stringify(val); // Serialize
867
- const oldData = yield this.redis.getset(key, newData);
868
- if (oldData !== null)
869
- return JSON.parse(oldData); // Deserialize
870
- });
871
- }
872
- /**
873
- * CacheBackend.pop implementation
874
- */
875
- pop(key) {
876
- return __awaiter(this, void 0, void 0, function* () {
877
- const [[err, data]] = yield this.redis
878
- .multi()
879
- .get(key) // read
880
- .del(key) // and delete
881
- .exec();
882
- if (!err && data !== null)
883
- return JSON.parse(data);
884
- });
885
- }
886
- /**
887
- * CacheBackend.incr implementation
888
- */
889
- incr(key, increment) {
890
- return __awaiter(this, void 0, void 0, function* () {
891
- return yield this.redis.incrbyfloat(key, increment); // Support both integer and floating point
892
- });
893
- }
894
- /**
895
- * CacheBackend.keys implementation
896
- */
897
- keys() {
898
- return __awaiter(this, void 0, void 0, function* () {
899
- return yield this.redis.keys('*');
900
- });
901
- }
902
- /**
903
- * CacheBackend.has implementation
904
- */
905
- has(key) {
906
- return __awaiter(this, void 0, void 0, function* () {
907
- return (yield this.redis.exists(key)) > 0; // 1: exists / 0: does not exist
908
- });
909
- }
910
- /**
911
- * CacheBackend.del implementation
912
- */
913
- del(key) {
914
- return __awaiter(this, void 0, void 0, function* () {
915
- return (yield this.redis.del(key)) === 1; // number of keys removed
916
- });
917
- }
918
- /**
919
- * CacheBackend.expire implementation
920
- */
921
- expire(key, ttl) {
922
- return __awaiter(this, void 0, void 0, function* () {
923
- const ret = ttl > 0 ? yield this.redis.expire(key, ttl) : yield this.redis.persist(key);
924
- return ret > 0; // 1: success / 0: key does not exist
925
- });
926
- }
927
- /**
928
- * CacheBackend.ttl implementation
929
- */
930
- ttl(key) {
931
- return __awaiter(this, void 0, void 0, function* () {
932
- const ms = yield this.redis.pttl(key); // -2: key does not exist / -1: no timeout
933
- if (ms >= 0)
934
- return ms;
935
- if (ms === -1)
936
- return 0;
937
- });
938
- }
939
- /**
940
- * CacheBackend.close implementation
941
- */
942
- close() {
943
- return __awaiter(this, void 0, void 0, function* () {
944
- yield this.redis.quit();
945
- });
946
- }
947
- }
948
- //# sourceMappingURL=cache-service.js.map