UNPKG

@universis/janitor

Version:

Universis api plugin for handling user authorization and rate limiting

125 lines (115 loc) 4.83 kB
import { TraceUtils } from '@themost/common'; import { RedisStore } from 'rate-limit-redis'; import { Redis } from 'ioredis'; import '@themost/promise-sequence'; let superLoadIncrementScript; let superLoadGetScript; function noLoadGetScript() { // } function noLoadIncrementScript() { // } if (RedisStore.prototype.loadIncrementScript.name === 'loadIncrementScript') { // get super method for future use superLoadIncrementScript = RedisStore.prototype.loadIncrementScript; RedisStore.prototype.loadIncrementScript = noLoadIncrementScript; } if (RedisStore.prototype.loadGetScript.name === 'loadGetScript') { // get super method superLoadGetScript = RedisStore.prototype.loadGetScript; RedisStore.prototype.loadGetScript = noLoadGetScript; } class RedisClientStore extends RedisStore { /** * @type {import('redis').RedisClientType} */ client; /** * * @param {import('@themost/common').ApplicationService} service * @param {{windowMs: number}} options */ constructor(service, options) { super({ /** * @param {...string} args * @returns {Promise<*>} */ sendCommand: function () { const args = Array.from(arguments); const [command] = args.splice(0, 1); const self = this; if (command === 'SCRIPT') { const connectOptions = service.getApplication().getConfiguration().getSourceAt('settings/redis/options') || { host: '127.0.0.1', port: 6379 }; const client = new Redis(connectOptions); return client.call(command, args).catch((error) => { if (error instanceof TypeError && error.message === 'Invalid argument type') { TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args)); } return Promise.reject(error); }).finally(() => { if (client.isOpen) { client.disconnect().catch((errDisconnect) => { TraceUtils.error(errDisconnect); }); } }); } if (self.client == null) { const connectOptions = service.getApplication().getConfiguration().getSourceAt('settings/redis/options') || { host: '127.0.0.1', port: 6379 }; self.client = new Redis(connectOptions); } if (self.client.isOpen) { return self.client.call(command, args).catch((error) => { if (error instanceof TypeError && error.message === 'Invalid argument type') { TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args)); } return Promise.reject(error); }); } // send load script commands once return (() => { if (self.incrementScriptSha == null) { return this.postInit(); } return Promise.resolve(); })().then(() => { // send command args[0] = self.incrementScriptSha; return self.client.call(command, args).catch((error) => { if (error instanceof TypeError && error.message === 'Invalid argument type') { TraceUtils.warn('RedisClientStore: Invalid argument type: ' + JSON.stringify(args)); } return Promise.reject(error); }); }); } }); this.init(options); TraceUtils.debug('RedisClientStore: Starting up and loading increment and get scripts.'); void this.postInit().then(() => { TraceUtils.debug('RedisClientStore: Successfully loaded increment and get scripts.'); }).catch((err) => { TraceUtils.error('RedisClientStore: Failed to load increment and get scripts.'); TraceUtils.error(err); }); } async postInit() { const [incrementScriptSha, getScriptSha] = await Promise.sequence([ () => superLoadIncrementScript.call(this), () => superLoadGetScript.call(this) ]); this.incrementScriptSha = incrementScriptSha; this.getScriptSha = getScriptSha; } } export { RedisClientStore }