redis-smq-common
Version:
RedisSMQ Common Library provides many components that are mainly used by RedisSMQ and RedisSMQ Monitor.
196 lines • 6.82 kB
JavaScript
import fs from 'fs';
import { resolve } from 'path';
import { async } from '../../async/index.js';
import { env } from '../../env/index.js';
import { CallbackEmptyReplyError } from '../../errors/index.js';
import { EventEmitter } from '../../event/index.js';
import { RedisClientError } from '../errors/index.js';
const dir = env.getCurrentDir();
export var ELuaScriptName;
(function (ELuaScriptName) {
ELuaScriptName["LPOPRPUSH"] = "LPOPRPUSH";
ELuaScriptName["ZPOPRPUSH"] = "ZPOPRPUSH";
})(ELuaScriptName || (ELuaScriptName = {}));
const luaScriptMap = {
[ELuaScriptName.LPOPRPUSH]: resolve(dir, '../lua-scripts/lpoprpush.lua'),
[ELuaScriptName.ZPOPRPUSH]: resolve(dir, '../lua-scripts/zpoprpush.lua'),
};
const minimalSupportedVersion = [4, 0, 0];
export class RedisClientAbstract extends EventEmitter {
static scripts = {};
static redisServerVersion = null;
connectionClosed = true;
init() {
async.series([
(cb) => this.validateRedisServerSupport(cb),
(cb) => this.loadBuiltInScriptFiles(cb),
], (err) => {
if (err)
this.emit('error', err);
else
this.emit('ready');
});
}
validateRedisVersion(major, feature = 0, minor = 0) {
if (!RedisClientAbstract.redisServerVersion) {
this.emit('error', new RedisClientError('UNKNOWN_REDIS_SERVER_VERSION'));
return false;
}
return (RedisClientAbstract.redisServerVersion[0] > major ||
(RedisClientAbstract.redisServerVersion[0] === major &&
RedisClientAbstract.redisServerVersion[1] >= feature &&
RedisClientAbstract.redisServerVersion[2] >= minor));
}
validateRedisServerSupport(cb) {
const validate = (cb) => {
const [major, feature, minor] = minimalSupportedVersion;
if (!this.validateRedisVersion(major, feature, minor))
cb(new RedisClientError('UNSUPPORTED_REDIS_SERVER_VERSION'));
else
cb();
};
if (!RedisClientAbstract.redisServerVersion) {
this.updateServerVersion((err) => {
if (err)
cb(err);
else
validate(cb);
});
}
else
validate(cb);
}
sscanAll(key, options, cb) {
const result = new Set();
const iterate = (cursor) => {
this.sscan(key, cursor, options, (err, reply) => {
if (err)
cb(err);
else if (!reply)
cb(new CallbackEmptyReplyError());
else {
reply.items.forEach((i) => result.add(i));
if (reply.cursor === '0')
cb(null, [...result]);
else
iterate(reply.cursor);
}
});
};
iterate('0');
}
hscanAll(key, options, cb) {
const result = {};
const iterate = (cursor) => {
this.hscan(key, cursor, options, (err, reply) => {
if (err)
cb(err);
else if (!reply)
cb(new CallbackEmptyReplyError());
else {
Object.assign(result, reply.result);
if (reply.cursor === '0')
cb(null, result);
else
iterate(reply.cursor);
}
});
};
iterate('0');
}
zpoprpush(source, destination, cb) {
this.runScript(ELuaScriptName.ZPOPRPUSH, [source, destination], [], (err, res) => {
if (err)
cb(err);
else
cb(null, typeof res === 'string' ? res : null);
});
}
lpoprpush(source, destination, cb) {
if (this.validateRedisVersion(6, 2)) {
this.lmove(source, destination, 'LEFT', 'RIGHT', cb);
}
else {
this.runScript(ELuaScriptName.LPOPRPUSH, [source, destination], [], (err, res) => {
if (err)
cb(err);
else
cb(null, typeof res === 'string' ? res : null);
});
}
}
updateServerVersion(cb) {
if (!RedisClientAbstract.redisServerVersion) {
this.getInfo((err, res) => {
if (err)
cb(err);
else if (!res)
cb(new CallbackEmptyReplyError());
else {
RedisClientAbstract.redisServerVersion = res
.split('\r\n')[1]
.split(':')[1]
.split('.')
.map((i) => Number(i));
cb();
}
});
}
else
cb();
}
loadBuiltInScriptFiles(cb) {
this.loadScriptFiles(luaScriptMap, (err) => cb(err));
}
loadScriptFiles(scriptMap, cb) {
const tasks = [];
const loadedScripts = {};
for (const name in scriptMap) {
if (!RedisClientAbstract.scripts[name]) {
tasks.push((cb) => {
fs.readFile(scriptMap[name], 'utf8', (err, content) => {
if (err)
return cb(err);
this.loadScript(content, (err, sha) => {
if (err)
return cb(err);
if (!sha)
return cb(new CallbackEmptyReplyError());
loadedScripts[name] = sha;
RedisClientAbstract.scripts[name] = sha;
cb();
});
});
});
}
}
if (!tasks.length)
return cb(null, loadedScripts);
async.series(tasks, (err) => {
if (err)
return cb(err);
cb(null, loadedScripts);
});
}
getScriptId(name) {
const id = RedisClientAbstract.scripts[name];
if (!id) {
return new RedisClientError(`ID of script [${name}] is missing`);
}
return id;
}
runScript(scriptName, keys, args, cb) {
const sha = this.getScriptId(scriptName);
if (sha instanceof Error)
cb(sha);
else {
this.evalsha(sha, [keys.length, ...keys, ...args], (err, res) => {
if (err)
cb(err);
else
cb(null, res);
});
}
}
}
//# sourceMappingURL=redis-client-abstract.js.map