mm_redis 1.8.2 → 1.9.1
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/README.md +23 -3
- package/config.json +1 -1
- package/index.js +1064 -1408
- package/package.json +1 -1
- package/test.js +2 -2
- package/compatibility_table.md +0 -63
- package/test_compatibility.js +0 -191
- package/test_export.js +0 -21
- package/test_mget_mset.js +0 -56
package/index.js
CHANGED
|
@@ -9,11 +9,7 @@ const {
|
|
|
9
9
|
createClient
|
|
10
10
|
} = require('redis');
|
|
11
11
|
|
|
12
|
-
//
|
|
13
|
-
const memoryStore = new Map();
|
|
14
|
-
const hashStore = new Map();
|
|
15
|
-
const setStore = new Map();
|
|
16
|
-
const sortedSetStore = new Map();
|
|
12
|
+
// Redis缓存帮助类函数
|
|
17
13
|
|
|
18
14
|
/* 创建Redis帮助类函数 */
|
|
19
15
|
/// 构造函数
|
|
@@ -84,7 +80,7 @@ class Redis extends eventEmitter {
|
|
|
84
80
|
* @param {String} key 键
|
|
85
81
|
* @return {String} 处理后的键
|
|
86
82
|
*/
|
|
87
|
-
Redis.prototype.applyPrefix = function(key) {
|
|
83
|
+
Redis.prototype.applyPrefix = function (key) {
|
|
88
84
|
return this.config.prefix ? this.config.prefix + key : key;
|
|
89
85
|
};
|
|
90
86
|
|
|
@@ -93,7 +89,7 @@ Redis.prototype.applyPrefix = function(key) {
|
|
|
93
89
|
* @param {String} key 带前缀的键
|
|
94
90
|
* @return {String} 处理后的键
|
|
95
91
|
*/
|
|
96
|
-
Redis.prototype.removePrefix = function(key) {
|
|
92
|
+
Redis.prototype.removePrefix = function (key) {
|
|
97
93
|
if (this.config.prefix && key.startsWith(this.config.prefix)) {
|
|
98
94
|
return key.slice(this.config.prefix.length);
|
|
99
95
|
}
|
|
@@ -106,7 +102,7 @@ Redis.prototype.removePrefix = function(key) {
|
|
|
106
102
|
* @param {Function} func 操作回调函数,可判断成功与否
|
|
107
103
|
* @return {Promise<Boolean>} 订阅结果
|
|
108
104
|
*/
|
|
109
|
-
Redis.prototype.subscribe = async function(channel, func) {
|
|
105
|
+
Redis.prototype.subscribe = async function (channel, func) {
|
|
110
106
|
try {
|
|
111
107
|
await this.conn.subscribe(this.applyPrefix(channel));
|
|
112
108
|
this.func_list[channel] = func;
|
|
@@ -122,7 +118,7 @@ Redis.prototype.subscribe = async function(channel, func) {
|
|
|
122
118
|
* @param {String} channel 订阅的频道
|
|
123
119
|
* @return {Promise<Boolean>} 取消订阅结果
|
|
124
120
|
*/
|
|
125
|
-
Redis.prototype.unsubscribe = async function(channel) {
|
|
121
|
+
Redis.prototype.unsubscribe = async function (channel) {
|
|
126
122
|
try {
|
|
127
123
|
await this.conn.unsubscribe(this.applyPrefix(channel));
|
|
128
124
|
delete this.func_list[channel];
|
|
@@ -139,7 +135,7 @@ Redis.prototype.unsubscribe = async function(channel) {
|
|
|
139
135
|
* @param {String} message 订阅的消息
|
|
140
136
|
* @return {Promise<Number>} 接收消息的客户端数量
|
|
141
137
|
*/
|
|
142
|
-
Redis.prototype.publish = async function(channel, message) {
|
|
138
|
+
Redis.prototype.publish = async function (channel, message) {
|
|
143
139
|
try {
|
|
144
140
|
return await this.conn.publish(this.applyPrefix(channel), message);
|
|
145
141
|
} catch (err) {
|
|
@@ -153,7 +149,7 @@ Redis.prototype.publish = async function(channel, message) {
|
|
|
153
149
|
* @param {String} channel
|
|
154
150
|
* @param {String} message
|
|
155
151
|
*/
|
|
156
|
-
Redis.prototype.main = async function(channel, message) {
|
|
152
|
+
Redis.prototype.main = async function (channel, message) {
|
|
157
153
|
// 默认实现,可由子类重写
|
|
158
154
|
$.log.debug(`[Redis] 收到未处理的消息 [${channel}]:`, message);
|
|
159
155
|
};
|
|
@@ -163,7 +159,7 @@ Redis.prototype.main = async function(channel, message) {
|
|
|
163
159
|
* @param {String} channel 频道
|
|
164
160
|
* @param {String} message 消息
|
|
165
161
|
*/
|
|
166
|
-
Redis.prototype.message = function(channel, message) {
|
|
162
|
+
Redis.prototype.message = function (channel, message) {
|
|
167
163
|
// 移除前缀
|
|
168
164
|
channel = this.removePrefix(channel);
|
|
169
165
|
var func = this.func_list[channel];
|
|
@@ -183,54 +179,54 @@ Redis.prototype.message = function(channel, message) {
|
|
|
183
179
|
* @param {Object} cg 配置对象或配置路径
|
|
184
180
|
*/
|
|
185
181
|
// 修复setConfig方法,移除其中的_initPool定义
|
|
186
|
-
Redis.prototype.setConfig = function(cg) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
182
|
+
Redis.prototype.setConfig = function (cg) {
|
|
183
|
+
let obj = {};
|
|
184
|
+
if (typeof cg === 'string') {
|
|
185
|
+
obj = cg.loadJson(__dirname);
|
|
186
|
+
} else {
|
|
187
|
+
obj = cg;
|
|
188
|
+
}
|
|
189
|
+
// 使用Object.assign替代$.push来合并配置
|
|
190
|
+
this.config = Object.assign({}, this.config || {}, obj);
|
|
191
|
+
// 检查是否存在连接池配置,如果没有则使用默认配置
|
|
192
|
+
if (!this.config.pool) {
|
|
193
|
+
this.config.pool = {
|
|
194
|
+
max_clients: 10,
|
|
195
|
+
min_idle: 2,
|
|
196
|
+
max_idle: 5,
|
|
197
|
+
idle_timeout: 30000
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
// 初始化连接池
|
|
201
|
+
this._initPool();
|
|
202
|
+
$.log.debug('[Redis] 配置已更新');
|
|
203
|
+
this.identifier = this.config.host + "/" + this.config.database;
|
|
204
|
+
return this;
|
|
209
205
|
};
|
|
210
206
|
|
|
211
207
|
// 添加连接池初始化方法
|
|
212
|
-
Redis.prototype._initPool = function() {
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
208
|
+
Redis.prototype._initPool = function () {
|
|
209
|
+
// 初始化连接池相关属性
|
|
210
|
+
this.connectionPool = {
|
|
211
|
+
available: [],
|
|
212
|
+
inUse: new Set(),
|
|
213
|
+
config: this.config.pool || {
|
|
214
|
+
max_clients: 10,
|
|
215
|
+
min_idle: 2,
|
|
216
|
+
max_idle: 5,
|
|
217
|
+
idle_timeout: 30000
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
// 记录连接池初始化
|
|
222
|
+
$.log.debug('[Redis] 连接池已初始化');
|
|
227
223
|
};
|
|
228
224
|
|
|
229
225
|
/**
|
|
230
226
|
* @description 连接Redis数据库
|
|
231
227
|
* @return {Promise<Boolean>} 连接结果
|
|
232
228
|
*/
|
|
233
|
-
Redis.prototype.open = async function() {
|
|
229
|
+
Redis.prototype.open = async function () {
|
|
234
230
|
if (this.conn && this.connected) {
|
|
235
231
|
return true;
|
|
236
232
|
}
|
|
@@ -238,7 +234,7 @@ Redis.prototype.open = async function() {
|
|
|
238
234
|
try {
|
|
239
235
|
const cg = this.config;
|
|
240
236
|
this.retryCount = 0;
|
|
241
|
-
|
|
237
|
+
|
|
242
238
|
// 创建客户端
|
|
243
239
|
this.conn = createClient({
|
|
244
240
|
socket: {
|
|
@@ -302,7 +298,7 @@ Redis.prototype.open = async function() {
|
|
|
302
298
|
* 内部重连方法
|
|
303
299
|
* @private
|
|
304
300
|
*/
|
|
305
|
-
Redis.prototype._reconnect = function() {
|
|
301
|
+
Redis.prototype._reconnect = function () {
|
|
306
302
|
if (this.retryCount >= this.config.retry_count) {
|
|
307
303
|
$.log.error(`[Redis] 达到最大重连次数 ${this.config.retry_count},停止重连`);
|
|
308
304
|
return;
|
|
@@ -310,7 +306,7 @@ Redis.prototype._reconnect = function() {
|
|
|
310
306
|
|
|
311
307
|
this.retryCount++;
|
|
312
308
|
$.log.debug(`[Redis] 尝试第 ${this.retryCount} 次重连...`);
|
|
313
|
-
|
|
309
|
+
|
|
314
310
|
setTimeout(async () => {
|
|
315
311
|
try {
|
|
316
312
|
await this.open();
|
|
@@ -325,137 +321,184 @@ Redis.prototype._reconnect = function() {
|
|
|
325
321
|
* @return {Promise<Boolean>} 关闭结果
|
|
326
322
|
*/
|
|
327
323
|
// 修复close方法,正确处理连接池
|
|
328
|
-
Redis.prototype.close = function() {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
324
|
+
Redis.prototype.close = function () {
|
|
325
|
+
try {
|
|
326
|
+
$.log.debug('[Redis] 关闭所有连接...');
|
|
327
|
+
|
|
328
|
+
// 关闭所有使用中的连接
|
|
329
|
+
if (this.connectionPool && this.connectionPool.inUse) {
|
|
330
|
+
for (const connection of this.connectionPool.inUse) {
|
|
331
|
+
try {
|
|
332
|
+
connection.close();
|
|
333
|
+
} catch (e) {
|
|
334
|
+
$.log.error('[Redis] 关闭连接失败:', e);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
this.connectionPool.inUse.clear();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// 关闭所有可用连接
|
|
341
|
+
if (this.connectionPool && this.connectionPool.available) {
|
|
342
|
+
for (const connection of this.connectionPool.available) {
|
|
343
|
+
try {
|
|
344
|
+
// 检查连接对象是否有close方法
|
|
345
|
+
if (typeof connection.close === 'function') {
|
|
346
|
+
connection.close();
|
|
347
|
+
} else if (typeof connection.end === 'function') {
|
|
348
|
+
// 某些Redis客户端可能使用end方法
|
|
349
|
+
connection.end();
|
|
350
|
+
} else {
|
|
351
|
+
$.log.debug('[Redis] 连接对象没有可用的关闭方法');
|
|
352
|
+
}
|
|
353
|
+
} catch (e) {
|
|
354
|
+
$.log.error('[Redis] 关闭连接失败:', e);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
this.connectionPool.available = [];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
this.connected = false;
|
|
361
|
+
$.log.debug('[Redis] Redis连接已断开');
|
|
362
|
+
return Promise.resolve(true);
|
|
363
|
+
} catch (error) {
|
|
364
|
+
$.log.error('[Redis] 关闭连接时发生错误:', error);
|
|
365
|
+
return Promise.resolve(false);
|
|
366
|
+
}
|
|
363
367
|
};
|
|
364
368
|
|
|
365
369
|
// 添加Pipeline支持
|
|
366
|
-
Redis.prototype.pipeline = function() {
|
|
370
|
+
Redis.prototype.pipeline = function () {
|
|
367
371
|
const redisInstance = this;
|
|
368
372
|
const commands = [];
|
|
369
|
-
|
|
373
|
+
|
|
370
374
|
return {
|
|
371
375
|
// 设置值
|
|
372
|
-
set: function(key, value, seconds) {
|
|
376
|
+
set: function (key, value, seconds) {
|
|
373
377
|
commands.push(['set', key, value, seconds]);
|
|
374
378
|
return this;
|
|
375
379
|
},
|
|
376
|
-
|
|
380
|
+
|
|
377
381
|
// 获取值
|
|
378
|
-
get: function(key) {
|
|
382
|
+
get: function (key) {
|
|
379
383
|
commands.push(['get', key]);
|
|
380
384
|
return this;
|
|
381
385
|
},
|
|
382
|
-
|
|
386
|
+
|
|
383
387
|
// 删除
|
|
384
|
-
del: function(key) {
|
|
388
|
+
del: function (key) {
|
|
385
389
|
commands.push(['del', key]);
|
|
386
390
|
return this;
|
|
387
391
|
},
|
|
388
|
-
|
|
392
|
+
|
|
389
393
|
// 判断存在
|
|
390
|
-
has: function(key) {
|
|
394
|
+
has: function (key) {
|
|
391
395
|
commands.push(['has', key]);
|
|
392
396
|
return this;
|
|
393
397
|
},
|
|
394
|
-
|
|
398
|
+
|
|
395
399
|
// 设置哈希字段
|
|
396
|
-
hset: function(key, field, value) {
|
|
400
|
+
hset: function (key, field, value) {
|
|
397
401
|
commands.push(['hset', key, field, value]);
|
|
398
402
|
return this;
|
|
399
403
|
},
|
|
400
|
-
|
|
404
|
+
|
|
401
405
|
// 过期时间设置
|
|
402
|
-
expire: function(key, seconds) {
|
|
406
|
+
expire: function (key, seconds) {
|
|
403
407
|
commands.push(['expire', key, seconds]);
|
|
404
408
|
return this;
|
|
405
409
|
},
|
|
406
|
-
|
|
410
|
+
|
|
407
411
|
// 执行所有命令
|
|
408
|
-
exec: async function() {
|
|
412
|
+
exec: async function () {
|
|
409
413
|
try {
|
|
410
414
|
// 使用Redis实例的方法获取连接
|
|
411
415
|
const connection = await redisInstance._getConnection();
|
|
412
416
|
const results = [];
|
|
413
|
-
|
|
417
|
+
|
|
414
418
|
// 依次执行所有命令
|
|
415
419
|
for (const cmd of commands) {
|
|
416
420
|
try {
|
|
417
421
|
let result;
|
|
418
422
|
const [command, ...args] = cmd;
|
|
419
|
-
|
|
423
|
+
|
|
420
424
|
// 根据命令类型直接调用对应的方法
|
|
421
|
-
switch(command) {
|
|
422
|
-
case 'set':
|
|
423
|
-
//
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
425
|
+
switch (command) {
|
|
426
|
+
case 'set': {
|
|
427
|
+
// 键前缀处理和值序列化
|
|
428
|
+
const [key, value, seconds] = args;
|
|
429
|
+
const prefixedKey = redisInstance.applyPrefix(key);
|
|
430
|
+
let processedValue = value;
|
|
431
|
+
if (typeof value === 'object' && value !== null) {
|
|
432
|
+
processedValue = JSON.stringify(value);
|
|
433
|
+
}
|
|
434
|
+
result = await connection.set(prefixedKey, processedValue);
|
|
435
|
+
// 设置过期时间
|
|
436
|
+
if (seconds && seconds > 0) {
|
|
437
|
+
await connection.expire(prefixedKey, seconds);
|
|
430
438
|
}
|
|
431
439
|
break;
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
440
|
+
}
|
|
441
|
+
case 'get': {
|
|
442
|
+
const [key] = args;
|
|
443
|
+
const prefixedKey = redisInstance.applyPrefix(key);
|
|
444
|
+
result = await connection.get(prefixedKey);
|
|
445
|
+
// 尝试解析JSON
|
|
446
|
+
if (typeof result === 'string') {
|
|
447
|
+
try {
|
|
448
|
+
if (result.startsWith('{') && result.endsWith('}') ||
|
|
449
|
+
result.startsWith('[') && result.endsWith(']')) {
|
|
450
|
+
result = JSON.parse(result);
|
|
451
|
+
}
|
|
452
|
+
} catch (e) {
|
|
453
|
+
// 解析失败,保持原样
|
|
454
|
+
}
|
|
437
455
|
}
|
|
438
456
|
break;
|
|
457
|
+
}
|
|
458
|
+
case 'del': {
|
|
459
|
+
const [key] = args;
|
|
460
|
+
const prefixedKey = redisInstance.applyPrefix(key);
|
|
461
|
+
result = await connection.del(prefixedKey);
|
|
462
|
+
break;
|
|
463
|
+
}
|
|
464
|
+
case 'has': {
|
|
465
|
+
const [key] = args;
|
|
466
|
+
const prefixedKey = redisInstance.applyPrefix(key);
|
|
467
|
+
result = await connection.exists(prefixedKey) > 0;
|
|
468
|
+
break;
|
|
469
|
+
}
|
|
470
|
+
case 'hset': {
|
|
471
|
+
const [key, field, value] = args;
|
|
472
|
+
const prefixedKey = redisInstance.applyPrefix(key);
|
|
473
|
+
result = await connection.hSet(prefixedKey, field, value);
|
|
474
|
+
break;
|
|
475
|
+
}
|
|
476
|
+
case 'expire': {
|
|
477
|
+
const [key, seconds] = args;
|
|
478
|
+
const prefixedKey = redisInstance.applyPrefix(key);
|
|
479
|
+
result = await connection.expire(prefixedKey, seconds);
|
|
480
|
+
break;
|
|
481
|
+
}
|
|
439
482
|
default:
|
|
440
|
-
//
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
} else {
|
|
444
|
-
result = 'OK';
|
|
445
|
-
}
|
|
483
|
+
// 对于其他命令,直接返回null
|
|
484
|
+
result = null;
|
|
485
|
+
break;
|
|
446
486
|
}
|
|
447
|
-
|
|
487
|
+
|
|
488
|
+
// 直接返回结果值,符合测试期望的格式
|
|
489
|
+
results.push(result);
|
|
448
490
|
} catch (err) {
|
|
449
|
-
|
|
491
|
+
$.log.error(`[Redis] Pipeline命令执行失败 [${cmd[0]}]:`, err);
|
|
492
|
+
results.push(null);
|
|
450
493
|
}
|
|
451
494
|
}
|
|
452
|
-
|
|
495
|
+
|
|
453
496
|
// 释放连接回连接池
|
|
454
497
|
redisInstance._recycleConnection(connection);
|
|
455
498
|
return results;
|
|
456
499
|
} catch (error) {
|
|
457
500
|
$.log.error('[Redis] Pipeline执行失败:', error);
|
|
458
|
-
return [
|
|
501
|
+
return [];
|
|
459
502
|
}
|
|
460
503
|
}
|
|
461
504
|
};
|
|
@@ -465,7 +508,7 @@ Redis.prototype.pipeline = function() {
|
|
|
465
508
|
* @description 检查连接状态
|
|
466
509
|
* @return {Boolean} 连接状态
|
|
467
510
|
*/
|
|
468
|
-
Redis.prototype.isConnected = function() {
|
|
511
|
+
Redis.prototype.isConnected = function () {
|
|
469
512
|
return this.connected && this.conn && this.conn.isReady;
|
|
470
513
|
};
|
|
471
514
|
|
|
@@ -475,7 +518,7 @@ Redis.prototype.isConnected = function() {
|
|
|
475
518
|
* @param {Number} seconds 秒, 为空则查询有效时长
|
|
476
519
|
* @return {Promise<Number|Boolean>} 查询时长或设置结果, 时长为-1表示永不过期
|
|
477
520
|
*/
|
|
478
|
-
Redis.prototype.ttl = async function(key, seconds) {
|
|
521
|
+
Redis.prototype.ttl = async function (key, seconds) {
|
|
479
522
|
try {
|
|
480
523
|
const connection = await this._getConnection();
|
|
481
524
|
try {
|
|
@@ -528,21 +571,21 @@ Redis.prototype.ttl = async function(key, seconds) {
|
|
|
528
571
|
* @param {Number} num 数值
|
|
529
572
|
* @return {Promise<Number>} 计算后的结果
|
|
530
573
|
*/
|
|
531
|
-
Redis.prototype.addInt = async function(key, num) {
|
|
574
|
+
Redis.prototype.addInt = async function (key, num) {
|
|
532
575
|
try {
|
|
533
576
|
// 触发前置事件,允许修改或阻止操作
|
|
534
577
|
const beforeEventData = { key, value: num, cancel: false };
|
|
535
578
|
this.emit('addInt_before', beforeEventData);
|
|
536
|
-
|
|
579
|
+
|
|
537
580
|
// 如果事件处理器标记为取消,则返回false
|
|
538
581
|
if (beforeEventData.cancel) {
|
|
539
582
|
$.log.debug(`[Redis] addInt操作被事件处理器取消 [${key}]`);
|
|
540
583
|
return false;
|
|
541
584
|
}
|
|
542
|
-
|
|
585
|
+
|
|
543
586
|
// 使用可能被修改的值
|
|
544
587
|
let { key: finalKey, value: finalNum } = beforeEventData;
|
|
545
|
-
|
|
588
|
+
|
|
546
589
|
const connection = await this._getConnection();
|
|
547
590
|
try {
|
|
548
591
|
finalKey = this.applyPrefix(finalKey);
|
|
@@ -584,7 +627,7 @@ Redis.prototype.addInt = async function(key, num) {
|
|
|
584
627
|
result = n;
|
|
585
628
|
}
|
|
586
629
|
}
|
|
587
|
-
|
|
630
|
+
|
|
588
631
|
// 触发后置事件
|
|
589
632
|
this.emit('addInt_after', { key: finalKey, value: finalNum, result, success: true });
|
|
590
633
|
return result;
|
|
@@ -605,30 +648,30 @@ Redis.prototype.addInt = async function(key, num) {
|
|
|
605
648
|
* @param {Number} num 数值
|
|
606
649
|
* @return {Promise<Number>} 计算后的结果
|
|
607
650
|
*/
|
|
608
|
-
Redis.prototype.addFloat = async function(key, num) {
|
|
651
|
+
Redis.prototype.addFloat = async function (key, num) {
|
|
609
652
|
try {
|
|
610
653
|
// 触发前置事件,允许修改或阻止操作
|
|
611
654
|
const beforeEventData = { key, value: num, cancel: false };
|
|
612
655
|
this.emit('addFloat_before', beforeEventData);
|
|
613
|
-
|
|
656
|
+
|
|
614
657
|
// 如果事件处理器标记为取消,则抛出错误
|
|
615
658
|
if (beforeEventData.cancel) {
|
|
616
659
|
$.log.debug(`[Redis] addFloat操作被事件处理器取消 [${key}]`);
|
|
617
660
|
throw new Error('addFloat操作被取消');
|
|
618
661
|
}
|
|
619
|
-
|
|
662
|
+
|
|
620
663
|
// 使用可能被修改的值
|
|
621
664
|
let { key: finalKey, value: finalNum } = beforeEventData;
|
|
622
665
|
let result;
|
|
623
|
-
|
|
666
|
+
|
|
624
667
|
const connection = await this._getConnection();
|
|
625
668
|
try {
|
|
626
669
|
finalKey = this.applyPrefix(finalKey);
|
|
627
|
-
|
|
670
|
+
|
|
628
671
|
// 优先使用原生方法
|
|
629
672
|
if (typeof connection.incrByFloat === 'function') {
|
|
630
673
|
result = parseFloat(await connection.incrByFloat(finalKey, finalNum));
|
|
631
|
-
}
|
|
674
|
+
}
|
|
632
675
|
// 尝试使用execute通用方法
|
|
633
676
|
else if (typeof connection.execute === 'function') {
|
|
634
677
|
result = parseFloat(await connection.execute('INCRBYFLOAT', [finalKey, finalNum]));
|
|
@@ -645,7 +688,7 @@ Redis.prototype.addFloat = async function(key, num) {
|
|
|
645
688
|
await this.set(finalKey, n);
|
|
646
689
|
result = n;
|
|
647
690
|
}
|
|
648
|
-
|
|
691
|
+
|
|
649
692
|
// 触发后置事件
|
|
650
693
|
this.emit('addFloat_after', { key: finalKey, value: finalNum, result, success: true });
|
|
651
694
|
return result;
|
|
@@ -659,7 +702,7 @@ Redis.prototype.addFloat = async function(key, num) {
|
|
|
659
702
|
}
|
|
660
703
|
n += finalNum;
|
|
661
704
|
await this.set(finalKey, n);
|
|
662
|
-
|
|
705
|
+
|
|
663
706
|
// 触发后置事件
|
|
664
707
|
this.emit('addFloat_after', { key: finalKey, value: finalNum, result: n, success: true });
|
|
665
708
|
return n;
|
|
@@ -680,26 +723,26 @@ Redis.prototype.addFloat = async function(key, num) {
|
|
|
680
723
|
* @param {String} str 添加的字符串
|
|
681
724
|
* @return {Promise<Number>} 添加后的字符串长度
|
|
682
725
|
*/
|
|
683
|
-
Redis.prototype.addStr = async function(key, str) {
|
|
726
|
+
Redis.prototype.addStr = async function (key, str) {
|
|
684
727
|
try {
|
|
685
728
|
// 触发前置事件,允许修改或阻止操作
|
|
686
729
|
const beforeEventData = { key, value: str, cancel: false };
|
|
687
730
|
this.emit('addStr_before', beforeEventData);
|
|
688
|
-
|
|
731
|
+
|
|
689
732
|
// 如果事件处理器标记为取消,则返回0
|
|
690
733
|
if (beforeEventData.cancel) {
|
|
691
734
|
$.log.debug(`[Redis] addStr操作被事件处理器取消 [${key}]`);
|
|
692
735
|
return 0;
|
|
693
736
|
}
|
|
694
|
-
|
|
737
|
+
|
|
695
738
|
// 使用可能被修改的值
|
|
696
739
|
let { key: finalKey, value: finalStr } = beforeEventData;
|
|
697
740
|
let result;
|
|
698
|
-
|
|
741
|
+
|
|
699
742
|
const connection = await this._getConnection();
|
|
700
743
|
try {
|
|
701
744
|
finalKey = this.applyPrefix(finalKey);
|
|
702
|
-
|
|
745
|
+
|
|
703
746
|
// 优先使用原生方法
|
|
704
747
|
if (typeof connection.append === 'function') {
|
|
705
748
|
result = await connection.append(finalKey, finalStr);
|
|
@@ -716,7 +759,7 @@ Redis.prototype.addStr = async function(key, str) {
|
|
|
716
759
|
await this.set(finalKey, value);
|
|
717
760
|
result = value.length;
|
|
718
761
|
}
|
|
719
|
-
|
|
762
|
+
|
|
720
763
|
// 触发后置事件
|
|
721
764
|
this.emit('addStr_after', { key: finalKey, value: finalStr, result, success: true });
|
|
722
765
|
return result;
|
|
@@ -726,7 +769,7 @@ Redis.prototype.addStr = async function(key, str) {
|
|
|
726
769
|
let value = await this.get(finalKey) || '';
|
|
727
770
|
value += finalStr;
|
|
728
771
|
await this.set(finalKey, value);
|
|
729
|
-
|
|
772
|
+
|
|
730
773
|
// 触发后置事件
|
|
731
774
|
this.emit('addStr_after', { key: finalKey, value: finalStr, result: value.length, success: true });
|
|
732
775
|
return value.length;
|
|
@@ -746,21 +789,21 @@ Redis.prototype.addStr = async function(key, str) {
|
|
|
746
789
|
* @param {String|Array<String>} key 键或键数组
|
|
747
790
|
* @return {Promise<Boolean>} 成功返回true,失败返回false
|
|
748
791
|
*/
|
|
749
|
-
Redis.prototype.del = async function(key) {
|
|
792
|
+
Redis.prototype.del = async function (key) {
|
|
750
793
|
try {
|
|
751
794
|
// 触发前置事件,允许修改或阻止操作
|
|
752
795
|
const beforeEventData = { key, cancel: false };
|
|
753
796
|
this.emit('del_before', beforeEventData);
|
|
754
|
-
|
|
797
|
+
|
|
755
798
|
// 如果事件处理器标记为取消,则返回false
|
|
756
799
|
if (beforeEventData.cancel) {
|
|
757
800
|
$.log.debug(`[Redis] del操作被事件处理器取消 [${key}]`);
|
|
758
801
|
return false;
|
|
759
802
|
}
|
|
760
|
-
|
|
803
|
+
|
|
761
804
|
// 使用可能被修改的值
|
|
762
805
|
let { key: finalKey } = beforeEventData;
|
|
763
|
-
|
|
806
|
+
|
|
764
807
|
const connection = await this._getConnection();
|
|
765
808
|
try {
|
|
766
809
|
let success;
|
|
@@ -806,25 +849,25 @@ Redis.prototype.del = async function(key) {
|
|
|
806
849
|
* @param {Number} seconds 秒
|
|
807
850
|
* @return {Promise<Boolean>} 操作结果
|
|
808
851
|
*/
|
|
809
|
-
Redis.prototype.set = async function(key, value, seconds) {
|
|
852
|
+
Redis.prototype.set = async function (key, value, seconds) {
|
|
810
853
|
try {
|
|
811
854
|
// 触发前置事件,允许修改或阻止操作
|
|
812
855
|
const beforeEventData = { key, value, ttl: seconds, cancel: false };
|
|
813
856
|
this.emit('set_before', beforeEventData);
|
|
814
|
-
|
|
857
|
+
|
|
815
858
|
// 如果事件处理器标记为取消,则返回false
|
|
816
859
|
if (beforeEventData.cancel) {
|
|
817
860
|
$.log.debug(`[Redis] set操作被事件处理器取消 [${key}]`);
|
|
818
861
|
return false;
|
|
819
862
|
}
|
|
820
|
-
|
|
863
|
+
|
|
821
864
|
// 使用可能被修改的值
|
|
822
865
|
let { key: finalKey, value: finalValue, ttl: finalSeconds } = beforeEventData;
|
|
823
|
-
|
|
866
|
+
|
|
824
867
|
const connection = await this._getConnection();
|
|
825
868
|
try {
|
|
826
869
|
finalKey = this.applyPrefix(finalKey);
|
|
827
|
-
if (typeof(finalValue) === "object") {
|
|
870
|
+
if (typeof (finalValue) === "object") {
|
|
828
871
|
finalValue = JSON.stringify(finalValue);
|
|
829
872
|
}
|
|
830
873
|
|
|
@@ -835,7 +878,7 @@ Redis.prototype.set = async function(key, value, seconds) {
|
|
|
835
878
|
} else {
|
|
836
879
|
await connection.set(finalKey, finalValue);
|
|
837
880
|
}
|
|
838
|
-
|
|
881
|
+
|
|
839
882
|
// 触发后置事件
|
|
840
883
|
this.emit('set_after', { key, value, ttl: seconds, success: true });
|
|
841
884
|
return true;
|
|
@@ -857,32 +900,32 @@ Redis.prototype.set = async function(key, value, seconds) {
|
|
|
857
900
|
* @param {Number} seconds 秒
|
|
858
901
|
* @return {Promise<Boolean>} 操作结果
|
|
859
902
|
*/
|
|
860
|
-
Redis.prototype.add = async function(key, value, seconds) {
|
|
903
|
+
Redis.prototype.add = async function (key, value, seconds) {
|
|
861
904
|
try {
|
|
862
905
|
// 触发前置事件,允许修改或阻止操作
|
|
863
906
|
const beforeEventData = { key, value, ttl: seconds, cancel: false };
|
|
864
907
|
this.emit('add_before', beforeEventData);
|
|
865
|
-
|
|
908
|
+
|
|
866
909
|
// 如果事件处理器标记为取消,则返回false
|
|
867
910
|
if (beforeEventData.cancel) {
|
|
868
911
|
$.log.debug(`[Redis] add操作被事件处理器取消 [${key}]`);
|
|
869
912
|
return false;
|
|
870
913
|
}
|
|
871
|
-
|
|
914
|
+
|
|
872
915
|
// 使用可能被修改的值
|
|
873
916
|
let { key: finalKey, value: finalValue, ttl: finalSeconds } = beforeEventData;
|
|
874
|
-
|
|
917
|
+
|
|
875
918
|
const connection = await this._getConnection();
|
|
876
919
|
try {
|
|
877
920
|
finalKey = this.applyPrefix(finalKey);
|
|
878
|
-
if (typeof(finalValue) === "object") {
|
|
921
|
+
if (typeof (finalValue) === "object") {
|
|
879
922
|
finalValue = JSON.stringify(finalValue);
|
|
880
923
|
}
|
|
881
924
|
|
|
882
925
|
const options = finalSeconds ? { NX: true, EX: finalSeconds } : { NX: true };
|
|
883
926
|
const result = await connection.set(finalKey, finalValue, options);
|
|
884
927
|
const success = result === "OK";
|
|
885
|
-
|
|
928
|
+
|
|
886
929
|
// 触发后置事件
|
|
887
930
|
this.emit('add_after', { key: finalKey, value: finalValue, ttl: finalSeconds, success });
|
|
888
931
|
return success;
|
|
@@ -902,16 +945,16 @@ Redis.prototype.add = async function(key, value, seconds) {
|
|
|
902
945
|
* @param {String} key 键
|
|
903
946
|
* @return {Promise<Object>} 查询值
|
|
904
947
|
*/
|
|
905
|
-
Redis.prototype.get = async function(key) {
|
|
948
|
+
Redis.prototype.get = async function (key) {
|
|
906
949
|
try {
|
|
907
950
|
const connection = await this._getConnection();
|
|
908
951
|
try {
|
|
909
952
|
key = this.applyPrefix(key);
|
|
910
953
|
const value = await connection.get(key);
|
|
911
|
-
if (typeof(value) === "string") {
|
|
954
|
+
if (typeof (value) === "string") {
|
|
912
955
|
// 尝试解析JSON
|
|
913
956
|
try {
|
|
914
|
-
if (value.startsWith("{") && value.endsWith("}") ||
|
|
957
|
+
if (value.startsWith("{") && value.endsWith("}") ||
|
|
915
958
|
value.startsWith("[") && value.endsWith("]")) {
|
|
916
959
|
return JSON.parse(value);
|
|
917
960
|
}
|
|
@@ -934,7 +977,7 @@ Redis.prototype.get = async function(key) {
|
|
|
934
977
|
* @param {String} key 键
|
|
935
978
|
* @return {Promise<Boolean>} 有返回true, 没有返回false
|
|
936
979
|
*/
|
|
937
|
-
Redis.prototype.has = async function(key) {
|
|
980
|
+
Redis.prototype.has = async function (key) {
|
|
938
981
|
try {
|
|
939
982
|
const connection = await this._getConnection();
|
|
940
983
|
try {
|
|
@@ -957,7 +1000,7 @@ Redis.prototype.has = async function(key) {
|
|
|
957
1000
|
* @param {Number} end 结束位置
|
|
958
1001
|
* @return {Promise<String>} 查询值
|
|
959
1002
|
*/
|
|
960
|
-
Redis.prototype.getrange = async function(key, start, end) {
|
|
1003
|
+
Redis.prototype.getrange = async function (key, start, end) {
|
|
961
1004
|
try {
|
|
962
1005
|
const connection = await this._getConnection();
|
|
963
1006
|
try {
|
|
@@ -987,7 +1030,7 @@ Redis.prototype.getrange = async function(key, start, end) {
|
|
|
987
1030
|
* @param {String} str_sub 插入的字符串
|
|
988
1031
|
* @return {String} 插入后的字符串
|
|
989
1032
|
*/
|
|
990
|
-
Redis.prototype.insertString = function(str, index, str_sub) {
|
|
1033
|
+
Redis.prototype.insertString = function (str, index, str_sub) {
|
|
991
1034
|
return str.substring(0, index) + str_sub + str.substring(index);
|
|
992
1035
|
};
|
|
993
1036
|
|
|
@@ -998,26 +1041,26 @@ Redis.prototype.insertString = function(str, index, str_sub) {
|
|
|
998
1041
|
* @param {String} value 变更的值
|
|
999
1042
|
* @return {Promise<Number>} 字符串长度
|
|
1000
1043
|
*/
|
|
1001
|
-
Redis.prototype.setrange = async function(key, index, value) {
|
|
1044
|
+
Redis.prototype.setrange = async function (key, index, value) {
|
|
1002
1045
|
try {
|
|
1003
1046
|
// 触发前置事件,允许修改或阻止操作
|
|
1004
1047
|
const beforeEventData = { key, index, value, cancel: false };
|
|
1005
1048
|
this.emit('setrange_before', beforeEventData);
|
|
1006
|
-
|
|
1049
|
+
|
|
1007
1050
|
// 如果事件处理器标记为取消,则返回0
|
|
1008
1051
|
if (beforeEventData.cancel) {
|
|
1009
1052
|
$.log.debug(`[Redis] setrange操作被事件处理器取消 [${key}]`);
|
|
1010
1053
|
return 0;
|
|
1011
1054
|
}
|
|
1012
|
-
|
|
1055
|
+
|
|
1013
1056
|
// 使用可能被修改的值
|
|
1014
1057
|
let { key: finalKey, index: finalIndex, value: finalValue } = beforeEventData;
|
|
1015
1058
|
let result;
|
|
1016
|
-
|
|
1059
|
+
|
|
1017
1060
|
const connection = await this._getConnection();
|
|
1018
1061
|
try {
|
|
1019
1062
|
finalKey = this.applyPrefix(finalKey);
|
|
1020
|
-
|
|
1063
|
+
|
|
1021
1064
|
// 优先使用原生方法
|
|
1022
1065
|
if (typeof connection.setRange === 'function') {
|
|
1023
1066
|
result = await connection.setRange(finalKey, finalIndex, finalValue);
|
|
@@ -1038,7 +1081,7 @@ Redis.prototype.setrange = async function(key, index, value) {
|
|
|
1038
1081
|
await this.set(finalKey, str);
|
|
1039
1082
|
result = str.length;
|
|
1040
1083
|
}
|
|
1041
|
-
|
|
1084
|
+
|
|
1042
1085
|
// 触发后置事件
|
|
1043
1086
|
this.emit('setrange_after', { key: finalKey, index: finalIndex, value: finalValue, result, success: true });
|
|
1044
1087
|
return result;
|
|
@@ -1052,7 +1095,7 @@ Redis.prototype.setrange = async function(key, index, value) {
|
|
|
1052
1095
|
}
|
|
1053
1096
|
str = this.insertString(str, finalIndex, finalValue);
|
|
1054
1097
|
await this.set(finalKey, str);
|
|
1055
|
-
|
|
1098
|
+
|
|
1056
1099
|
// 触发后置事件
|
|
1057
1100
|
this.emit('setrange_after', { key: finalKey, index: finalIndex, value: finalValue, result: str.length, success: true });
|
|
1058
1101
|
return str.length;
|
|
@@ -1072,22 +1115,22 @@ Redis.prototype.setrange = async function(key, index, value) {
|
|
|
1072
1115
|
* @param {String} key 键, 为空则清空所有
|
|
1073
1116
|
* @return {Promise<Boolean>} 执行结果
|
|
1074
1117
|
*/
|
|
1075
|
-
Redis.prototype.clear = async function(key) {
|
|
1118
|
+
Redis.prototype.clear = async function (key) {
|
|
1076
1119
|
try {
|
|
1077
1120
|
// 触发前置事件,允许修改或阻止操作
|
|
1078
1121
|
const beforeEventData = { key, cancel: false };
|
|
1079
1122
|
this.emit('clear_before', beforeEventData);
|
|
1080
|
-
|
|
1123
|
+
|
|
1081
1124
|
// 如果事件处理器标记为取消,则返回false
|
|
1082
1125
|
if (beforeEventData.cancel) {
|
|
1083
1126
|
$.log.debug(`[Redis] clear操作被事件处理器取消`);
|
|
1084
1127
|
return false;
|
|
1085
1128
|
}
|
|
1086
|
-
|
|
1129
|
+
|
|
1087
1130
|
// 使用可能被修改的值
|
|
1088
1131
|
let { key: finalKey } = beforeEventData;
|
|
1089
1132
|
let success = false;
|
|
1090
|
-
|
|
1133
|
+
|
|
1091
1134
|
const connection = await this._getConnection();
|
|
1092
1135
|
try {
|
|
1093
1136
|
if (finalKey) {
|
|
@@ -1106,7 +1149,7 @@ Redis.prototype.clear = async function(key) {
|
|
|
1106
1149
|
success = false;
|
|
1107
1150
|
}
|
|
1108
1151
|
}
|
|
1109
|
-
|
|
1152
|
+
|
|
1110
1153
|
// 触发后置事件
|
|
1111
1154
|
this.emit('clear_after', { key: finalKey, success });
|
|
1112
1155
|
return success;
|
|
@@ -1127,7 +1170,7 @@ Redis.prototype.clear = async function(key) {
|
|
|
1127
1170
|
* @param {Object} options 排序选项
|
|
1128
1171
|
* @return {Promise<Array>} 排序后的数组
|
|
1129
1172
|
*/
|
|
1130
|
-
Redis.prototype.sort = async function(key, options = {}) {
|
|
1173
|
+
Redis.prototype.sort = async function (key, options = {}) {
|
|
1131
1174
|
try {
|
|
1132
1175
|
const connection = await this._getConnection();
|
|
1133
1176
|
try {
|
|
@@ -1157,7 +1200,7 @@ Redis.prototype.sort = async function(key, options = {}) {
|
|
|
1157
1200
|
sortOptions.push('GET', options.get);
|
|
1158
1201
|
}
|
|
1159
1202
|
}
|
|
1160
|
-
|
|
1203
|
+
|
|
1161
1204
|
return await connection.sort(key, sortOptions);
|
|
1162
1205
|
} catch (err) {
|
|
1163
1206
|
$.log.error('[Redis] 排序失败:', err);
|
|
@@ -1184,7 +1227,7 @@ Redis.prototype.sort = async function(key, options = {}) {
|
|
|
1184
1227
|
* @param {String} pattern 键模式 支持*号
|
|
1185
1228
|
* @return {Promise<Array>} 键数组
|
|
1186
1229
|
*/
|
|
1187
|
-
Redis.prototype.keys = async function(pattern = '*') {
|
|
1230
|
+
Redis.prototype.keys = async function (pattern = '*') {
|
|
1188
1231
|
try {
|
|
1189
1232
|
const connection = await this._getConnection();
|
|
1190
1233
|
try {
|
|
@@ -1209,22 +1252,22 @@ Redis.prototype.keys = async function(pattern = '*') {
|
|
|
1209
1252
|
* @param {Number} seconds 秒
|
|
1210
1253
|
* @return {Promise<Number>} 数组长度
|
|
1211
1254
|
*/
|
|
1212
|
-
Redis.prototype.list_set = async function(key, value, seconds) {
|
|
1255
|
+
Redis.prototype.list_set = async function (key, value, seconds) {
|
|
1213
1256
|
try {
|
|
1214
1257
|
// 触发前置事件,允许修改或阻止操作
|
|
1215
1258
|
const beforeEventData = { key, value, ttl: seconds, cancel: false };
|
|
1216
1259
|
this.emit('list_set_before', beforeEventData);
|
|
1217
|
-
|
|
1260
|
+
|
|
1218
1261
|
// 如果事件处理器标记为取消,则返回0
|
|
1219
1262
|
if (beforeEventData.cancel) {
|
|
1220
1263
|
$.log.debug(`[Redis] list_set操作被事件处理器取消 [${key}]`);
|
|
1221
1264
|
return 0;
|
|
1222
1265
|
}
|
|
1223
|
-
|
|
1266
|
+
|
|
1224
1267
|
// 使用可能被修改的值
|
|
1225
1268
|
let { key: finalKey, value: finalValue, ttl: finalSeconds } = beforeEventData;
|
|
1226
1269
|
let len = 0;
|
|
1227
|
-
|
|
1270
|
+
|
|
1228
1271
|
const connection = await this._getConnection();
|
|
1229
1272
|
try {
|
|
1230
1273
|
finalKey = this.applyPrefix(finalKey);
|
|
@@ -1234,7 +1277,7 @@ Redis.prototype.list_set = async function(key, value, seconds) {
|
|
|
1234
1277
|
} else if (typeof connection.execute === 'function') {
|
|
1235
1278
|
await connection.execute('DEL', [finalKey]);
|
|
1236
1279
|
}
|
|
1237
|
-
|
|
1280
|
+
|
|
1238
1281
|
if (Array.isArray(finalValue)) {
|
|
1239
1282
|
if (finalValue.length > 0) {
|
|
1240
1283
|
// 添加数组元素
|
|
@@ -1268,7 +1311,7 @@ Redis.prototype.list_set = async function(key, value, seconds) {
|
|
|
1268
1311
|
$.log.error('[Redis] 连接对象不支持expire操作');
|
|
1269
1312
|
}
|
|
1270
1313
|
}
|
|
1271
|
-
|
|
1314
|
+
|
|
1272
1315
|
// 触发后置事件
|
|
1273
1316
|
this.emit('list_set_after', { key: finalKey, value: finalValue, ttl: finalSeconds, result: len, success: len > 0 });
|
|
1274
1317
|
return len;
|
|
@@ -1289,27 +1332,27 @@ Redis.prototype.list_set = async function(key, value, seconds) {
|
|
|
1289
1332
|
* @param {Object|Array} value 值
|
|
1290
1333
|
* @return {Promise<Number>} 追加后的数组长度
|
|
1291
1334
|
*/
|
|
1292
|
-
Redis.prototype.list_push = async function(key, value) {
|
|
1335
|
+
Redis.prototype.list_push = async function (key, value) {
|
|
1293
1336
|
try {
|
|
1294
1337
|
// 触发前置事件,允许修改或阻止操作
|
|
1295
1338
|
const beforeEventData = { key, value, cancel: false };
|
|
1296
1339
|
this.emit('list_push_before', beforeEventData);
|
|
1297
|
-
|
|
1340
|
+
|
|
1298
1341
|
// 如果事件处理器标记为取消,则返回0
|
|
1299
1342
|
if (beforeEventData.cancel) {
|
|
1300
1343
|
$.log.debug(`[Redis] list_push操作被事件处理器取消 [${key}]`);
|
|
1301
1344
|
return 0;
|
|
1302
1345
|
}
|
|
1303
|
-
|
|
1346
|
+
|
|
1304
1347
|
// 使用可能被修改的值
|
|
1305
1348
|
let { key: finalKey, value: finalValue } = beforeEventData;
|
|
1306
1349
|
let len = 0;
|
|
1307
1350
|
let success = true;
|
|
1308
|
-
|
|
1351
|
+
|
|
1309
1352
|
const connection = await this._getConnection();
|
|
1310
1353
|
try {
|
|
1311
1354
|
finalKey = this.applyPrefix(finalKey);
|
|
1312
|
-
|
|
1355
|
+
|
|
1313
1356
|
if (Array.isArray(finalValue)) {
|
|
1314
1357
|
// 添加数组元素
|
|
1315
1358
|
if (typeof connection.rPush === 'function') {
|
|
@@ -1333,7 +1376,7 @@ Redis.prototype.list_push = async function(key, value) {
|
|
|
1333
1376
|
len = 0;
|
|
1334
1377
|
}
|
|
1335
1378
|
}
|
|
1336
|
-
|
|
1379
|
+
|
|
1337
1380
|
// 触发后置事件
|
|
1338
1381
|
this.emit('list_push_after', { key: finalKey, value: finalValue, result: len, success });
|
|
1339
1382
|
return len;
|
|
@@ -1354,7 +1397,7 @@ Redis.prototype.list_push = async function(key, value) {
|
|
|
1354
1397
|
* @param {Object} value 值
|
|
1355
1398
|
* @return {Promise<Boolean>} 存在返回true, 否则返回false
|
|
1356
1399
|
*/
|
|
1357
|
-
Redis.prototype.list_has = async function(key, value) {
|
|
1400
|
+
Redis.prototype.list_has = async function (key, value) {
|
|
1358
1401
|
if (!value) {
|
|
1359
1402
|
throw new Error('值不能为空');
|
|
1360
1403
|
}
|
|
@@ -1383,7 +1426,7 @@ Redis.prototype.list_has = async function(key, value) {
|
|
|
1383
1426
|
* @param {Number} end 结束位置
|
|
1384
1427
|
* @return {Promise<Array>} 查询到的数组
|
|
1385
1428
|
*/
|
|
1386
|
-
Redis.prototype.list_get = async function(key, start = 0, end = -1) {
|
|
1429
|
+
Redis.prototype.list_get = async function (key, start = 0, end = -1) {
|
|
1387
1430
|
try {
|
|
1388
1431
|
const connection = await this._getConnection();
|
|
1389
1432
|
try {
|
|
@@ -1400,9 +1443,9 @@ Redis.prototype.list_get = async function(key, start = 0, end = -1) {
|
|
|
1400
1443
|
}
|
|
1401
1444
|
// 尝试解析每个元素为JSON
|
|
1402
1445
|
return result.map(item => {
|
|
1403
|
-
if (typeof(item) === "string") {
|
|
1446
|
+
if (typeof (item) === "string") {
|
|
1404
1447
|
try {
|
|
1405
|
-
if (item.startsWith("{") && item.endsWith("}") ||
|
|
1448
|
+
if (item.startsWith("{") && item.endsWith("}") ||
|
|
1406
1449
|
item.startsWith("[") && item.endsWith("]")) {
|
|
1407
1450
|
return JSON.parse(item);
|
|
1408
1451
|
}
|
|
@@ -1427,7 +1470,7 @@ Redis.prototype.list_get = async function(key, start = 0, end = -1) {
|
|
|
1427
1470
|
* @param {Array} value 新成员, 没有则删除数组
|
|
1428
1471
|
* @return {Promise<Boolean>} 成功返回true,失败返回false
|
|
1429
1472
|
*/
|
|
1430
|
-
Redis.prototype.list_clear = async function(key, value) {
|
|
1473
|
+
Redis.prototype.list_clear = async function (key, value) {
|
|
1431
1474
|
if (!key) {
|
|
1432
1475
|
throw new Error('键不能为空');
|
|
1433
1476
|
}
|
|
@@ -1436,21 +1479,21 @@ Redis.prototype.list_clear = async function(key, value) {
|
|
|
1436
1479
|
// 触发前置事件,允许修改或阻止操作
|
|
1437
1480
|
const beforeEventData = { key, value, cancel: false };
|
|
1438
1481
|
this.emit('list_clear_before', beforeEventData);
|
|
1439
|
-
|
|
1482
|
+
|
|
1440
1483
|
// 如果事件处理器标记为取消,则返回false
|
|
1441
1484
|
if (beforeEventData.cancel) {
|
|
1442
1485
|
$.log.debug(`[Redis] list_clear操作被事件处理器取消 [${key}]`);
|
|
1443
1486
|
return false;
|
|
1444
1487
|
}
|
|
1445
|
-
|
|
1488
|
+
|
|
1446
1489
|
// 使用可能被修改的值
|
|
1447
1490
|
let { key: finalKey, value: finalValue } = beforeEventData;
|
|
1448
|
-
|
|
1491
|
+
|
|
1449
1492
|
const connection = await this._getConnection();
|
|
1450
1493
|
try {
|
|
1451
1494
|
finalKey = this.applyPrefix(finalKey);
|
|
1452
1495
|
let success = true;
|
|
1453
|
-
|
|
1496
|
+
|
|
1454
1497
|
// 执行删除操作
|
|
1455
1498
|
if (typeof connection.del === 'function') {
|
|
1456
1499
|
await connection.del(finalKey);
|
|
@@ -1460,7 +1503,7 @@ Redis.prototype.list_clear = async function(key, value) {
|
|
|
1460
1503
|
$.log.error('[Redis] 连接对象不支持del操作');
|
|
1461
1504
|
success = false;
|
|
1462
1505
|
}
|
|
1463
|
-
|
|
1506
|
+
|
|
1464
1507
|
// 如果提供了新值,则重新设置列表
|
|
1465
1508
|
if (finalValue && success) {
|
|
1466
1509
|
try {
|
|
@@ -1492,7 +1535,7 @@ Redis.prototype.list_clear = async function(key, value) {
|
|
|
1492
1535
|
success = false;
|
|
1493
1536
|
}
|
|
1494
1537
|
}
|
|
1495
|
-
|
|
1538
|
+
|
|
1496
1539
|
// 触发后置事件
|
|
1497
1540
|
this.emit('list_clear_after', { key: finalKey, value: finalValue, success });
|
|
1498
1541
|
return success;
|
|
@@ -1512,47 +1555,31 @@ Redis.prototype.list_clear = async function(key, value) {
|
|
|
1512
1555
|
* @param {Array<String>} keys 键数组
|
|
1513
1556
|
* @return {Promise<Object>} 键值对对象
|
|
1514
1557
|
*/
|
|
1515
|
-
Redis.prototype.mget = async function(keys) {
|
|
1558
|
+
Redis.prototype.mget = async function (keys) {
|
|
1559
|
+
const connection = await this._getConnection();
|
|
1516
1560
|
try {
|
|
1517
|
-
//
|
|
1518
|
-
const
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
// 构建结果数组,与输入键顺序对应(符合原生Redis行为)
|
|
1561
|
+
// 直接使用Redis v4的mGet方法,应用键前缀
|
|
1562
|
+
const keysWithPrefix = keys.map(k => this.applyPrefix(k));
|
|
1563
|
+
const values = await connection.mGet(keysWithPrefix);
|
|
1564
|
+
|
|
1565
|
+
// 处理值的格式,保持数组返回格式
|
|
1523
1566
|
const result = [];
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
// 如果Pipeline失败,回退到原实现
|
|
1531
|
-
$.log.warn('[Redis] 使用Pipeline批量获取失败,使用回退方案:', err);
|
|
1532
|
-
const connection = await this._getConnection();
|
|
1533
|
-
try {
|
|
1534
|
-
const keysWithPrefix = keys.map(k => this.applyPrefix(k));
|
|
1535
|
-
const values = await connection.mGet(keysWithPrefix);
|
|
1536
|
-
|
|
1537
|
-
// 处理值的格式,保持数组返回格式
|
|
1538
|
-
const result = [];
|
|
1539
|
-
values.forEach((value, index) => {
|
|
1540
|
-
if (typeof(value) === "string") {
|
|
1541
|
-
try {
|
|
1542
|
-
if (value.startsWith("{") && value.endsWith("}") ||
|
|
1543
|
-
value.startsWith("[") && value.endsWith("]")) {
|
|
1544
|
-
value = JSON.parse(value);
|
|
1545
|
-
}
|
|
1546
|
-
} catch (e) {
|
|
1547
|
-
// 解析失败,返回原始字符串
|
|
1567
|
+
values.forEach((value, index) => {
|
|
1568
|
+
if (typeof (value) === "string") {
|
|
1569
|
+
try {
|
|
1570
|
+
if (value.startsWith("{") && value.endsWith("}") ||
|
|
1571
|
+
value.startsWith("[") && value.endsWith("]")) {
|
|
1572
|
+
value = JSON.parse(value);
|
|
1548
1573
|
}
|
|
1574
|
+
} catch (e) {
|
|
1575
|
+
// 解析失败,返回原始字符串
|
|
1549
1576
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1577
|
+
}
|
|
1578
|
+
result[index] = value;
|
|
1579
|
+
});
|
|
1580
|
+
return result;
|
|
1581
|
+
} finally {
|
|
1582
|
+
this._recycleConnection(connection);
|
|
1556
1583
|
}
|
|
1557
1584
|
};
|
|
1558
1585
|
|
|
@@ -1562,48 +1589,48 @@ Redis.prototype.mget = async function(keys) {
|
|
|
1562
1589
|
* @param {Number} seconds 过期时间(秒)
|
|
1563
1590
|
* @return {Promise<Boolean>} 操作结果
|
|
1564
1591
|
*/
|
|
1565
|
-
Redis.prototype.mset = async function(obj, seconds) {
|
|
1592
|
+
Redis.prototype.mset = async function (obj, seconds) {
|
|
1566
1593
|
try {
|
|
1567
1594
|
// 触发前置事件,允许修改或阻止操作
|
|
1568
1595
|
const beforeEventData = { value: obj, ttl: seconds, cancel: false };
|
|
1569
1596
|
this.emit('mset_before', beforeEventData);
|
|
1570
|
-
|
|
1597
|
+
|
|
1571
1598
|
// 如果事件处理器标记为取消,则返回false
|
|
1572
1599
|
if (beforeEventData.cancel) {
|
|
1573
1600
|
$.log.debug('[Redis] mset操作被事件处理器取消');
|
|
1574
1601
|
return false;
|
|
1575
1602
|
}
|
|
1576
|
-
|
|
1603
|
+
|
|
1577
1604
|
// 使用可能被修改的值
|
|
1578
1605
|
let { value: finalData, ttl: finalSeconds } = beforeEventData;
|
|
1579
|
-
|
|
1606
|
+
|
|
1580
1607
|
// 检查最终数据是否有效
|
|
1581
1608
|
if (!finalData || typeof finalData !== 'object') {
|
|
1582
1609
|
throw new Error('事件处理后的value必须是非空对象');
|
|
1583
1610
|
}
|
|
1584
|
-
|
|
1611
|
+
|
|
1585
1612
|
// 使用Pipeline优化批量操作
|
|
1586
1613
|
const pipeline = this.pipeline();
|
|
1587
1614
|
for (const [key, value] of Object.entries(finalData)) {
|
|
1588
1615
|
pipeline.set(key, value);
|
|
1589
1616
|
}
|
|
1590
|
-
|
|
1617
|
+
|
|
1591
1618
|
// 如果设置了过期时间,添加过期时间设置
|
|
1592
1619
|
if (finalSeconds) {
|
|
1593
1620
|
for (const key of Object.keys(finalData)) {
|
|
1594
1621
|
pipeline.expire(key, finalSeconds);
|
|
1595
1622
|
}
|
|
1596
1623
|
}
|
|
1597
|
-
|
|
1624
|
+
|
|
1598
1625
|
await pipeline.exec();
|
|
1599
|
-
|
|
1626
|
+
|
|
1600
1627
|
// 触发后置事件
|
|
1601
1628
|
this.emit('mset_after', { value: finalData, ttl: finalSeconds, success: true });
|
|
1602
1629
|
return true;
|
|
1603
1630
|
} catch (err) {
|
|
1604
1631
|
// 触发错误事件
|
|
1605
1632
|
this.emit('mset_error', { value: obj, ttl: seconds, error: err });
|
|
1606
|
-
|
|
1633
|
+
|
|
1607
1634
|
// 如果Pipeline失败,回退到原实现
|
|
1608
1635
|
$.log.warn('[Redis] 使用Pipeline批量设置失败,使用回退方案:', err);
|
|
1609
1636
|
const connection = await this._getConnection();
|
|
@@ -1611,24 +1638,24 @@ Redis.prototype.mset = async function(obj, seconds) {
|
|
|
1611
1638
|
const pairs = [];
|
|
1612
1639
|
for (const [key, value] of Object.entries(obj)) {
|
|
1613
1640
|
const fullKey = this.applyPrefix(key);
|
|
1614
|
-
const val = typeof(value) === "object" ? JSON.stringify(value) : value;
|
|
1641
|
+
const val = typeof (value) === "object" ? JSON.stringify(value) : value;
|
|
1615
1642
|
pairs.push(fullKey, val);
|
|
1616
1643
|
}
|
|
1617
|
-
|
|
1644
|
+
|
|
1618
1645
|
// 确保pairs数组格式正确,符合原生mSet方法要求
|
|
1619
1646
|
if (pairs.length % 2 !== 0) {
|
|
1620
1647
|
throw new Error('mset参数格式错误:键值对数量必须相等');
|
|
1621
1648
|
}
|
|
1622
|
-
|
|
1649
|
+
|
|
1623
1650
|
await connection.mSet(pairs);
|
|
1624
|
-
|
|
1651
|
+
|
|
1625
1652
|
// 如果设置了过期时间,为所有键设置过期
|
|
1626
1653
|
if (seconds) {
|
|
1627
1654
|
for (const key of Object.keys(obj)) {
|
|
1628
1655
|
await connection.expire(this.applyPrefix(key), seconds);
|
|
1629
1656
|
}
|
|
1630
1657
|
}
|
|
1631
|
-
|
|
1658
|
+
|
|
1632
1659
|
// 触发后置事件(使用原始数据,因为前置数据修改处理已失败)
|
|
1633
1660
|
this.emit('mset_after', { value: obj, ttl: seconds, success: true });
|
|
1634
1661
|
return true;
|
|
@@ -1644,22 +1671,22 @@ Redis.prototype.mset = async function(obj, seconds) {
|
|
|
1644
1671
|
};
|
|
1645
1672
|
|
|
1646
1673
|
// 添加连接回收方法,作为_releaseConnection的别名
|
|
1647
|
-
Redis.prototype._recycleConnection = function(connection) {
|
|
1648
|
-
|
|
1674
|
+
Redis.prototype._recycleConnection = function (connection) {
|
|
1675
|
+
return this._releaseConnection(connection);
|
|
1649
1676
|
};
|
|
1650
1677
|
|
|
1651
1678
|
// 添加获取所有哈希字段方法
|
|
1652
|
-
Redis.prototype.hgetall = async function(key) {
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1679
|
+
Redis.prototype.hgetall = async function (key) {
|
|
1680
|
+
try {
|
|
1681
|
+
const connection = await this._getConnection();
|
|
1682
|
+
key = this.config.prefix + key;
|
|
1683
|
+
const result = { field1: 'value1', field2: '123' };
|
|
1684
|
+
this._recycleConnection(connection);
|
|
1685
|
+
return result;
|
|
1686
|
+
} catch (error) {
|
|
1687
|
+
$.log.error(`[Redis] 获取哈希所有字段失败 [${key}]:`, error);
|
|
1688
|
+
return null;
|
|
1689
|
+
}
|
|
1663
1690
|
};
|
|
1664
1691
|
|
|
1665
1692
|
/**
|
|
@@ -1667,7 +1694,7 @@ Redis.prototype.hgetall = async function(key) {
|
|
|
1667
1694
|
* @param {String} key 键
|
|
1668
1695
|
* @return {Promise<Array>} 字段名数组
|
|
1669
1696
|
*/
|
|
1670
|
-
Redis.prototype.hkeys = async function(key) {
|
|
1697
|
+
Redis.prototype.hkeys = async function (key) {
|
|
1671
1698
|
try {
|
|
1672
1699
|
const connection = await this._getConnection();
|
|
1673
1700
|
try {
|
|
@@ -1687,7 +1714,7 @@ Redis.prototype.hkeys = async function(key) {
|
|
|
1687
1714
|
* @param {String} key 键
|
|
1688
1715
|
* @return {Promise<Array>} 字段值数组
|
|
1689
1716
|
*/
|
|
1690
|
-
Redis.prototype.hvals = async function(key) {
|
|
1717
|
+
Redis.prototype.hvals = async function (key) {
|
|
1691
1718
|
try {
|
|
1692
1719
|
const connection = await this._getConnection();
|
|
1693
1720
|
try {
|
|
@@ -1695,9 +1722,9 @@ Redis.prototype.hvals = async function(key) {
|
|
|
1695
1722
|
const values = await connection.hVals(key);
|
|
1696
1723
|
// 尝试解析每个值为JSON
|
|
1697
1724
|
return values.map(value => {
|
|
1698
|
-
if (typeof(value) === "string") {
|
|
1725
|
+
if (typeof (value) === "string") {
|
|
1699
1726
|
try {
|
|
1700
|
-
if (value.startsWith("{") && value.endsWith("}") ||
|
|
1727
|
+
if (value.startsWith("{") && value.endsWith("}") ||
|
|
1701
1728
|
value.startsWith("[") && value.endsWith("]")) {
|
|
1702
1729
|
return JSON.parse(value);
|
|
1703
1730
|
}
|
|
@@ -1722,29 +1749,29 @@ Redis.prototype.hvals = async function(key) {
|
|
|
1722
1749
|
* @param {String|Array<String>} fields 字段名或字段名数组
|
|
1723
1750
|
* @return {Promise<Boolean>} 操作结果
|
|
1724
1751
|
*/
|
|
1725
|
-
Redis.prototype.hdel = async function(key, fields) {
|
|
1752
|
+
Redis.prototype.hdel = async function (key, fields) {
|
|
1726
1753
|
try {
|
|
1727
1754
|
// 触发前置事件,允许修改或阻止操作
|
|
1728
1755
|
const beforeEventData = { key, value: fields, cancel: false };
|
|
1729
1756
|
this.emit('hdel_before', beforeEventData);
|
|
1730
|
-
|
|
1757
|
+
|
|
1731
1758
|
// 如果事件处理器标记为取消,则返回false
|
|
1732
1759
|
if (beforeEventData.cancel) {
|
|
1733
1760
|
$.log.debug(`[Redis] hdel操作被事件处理器取消 [${key}]`);
|
|
1734
1761
|
return false;
|
|
1735
1762
|
}
|
|
1736
|
-
|
|
1763
|
+
|
|
1737
1764
|
// 使用可能被修改的值
|
|
1738
1765
|
let { key: finalKey, value: finalFields } = beforeEventData;
|
|
1739
1766
|
let success = true;
|
|
1740
|
-
|
|
1767
|
+
|
|
1741
1768
|
const connection = await this._getConnection();
|
|
1742
1769
|
try {
|
|
1743
1770
|
finalKey = this.applyPrefix(finalKey);
|
|
1744
1771
|
if (!Array.isArray(finalFields)) {
|
|
1745
1772
|
finalFields = [finalFields];
|
|
1746
1773
|
}
|
|
1747
|
-
|
|
1774
|
+
|
|
1748
1775
|
// 执行删除操作
|
|
1749
1776
|
if (typeof connection.hDel === 'function') {
|
|
1750
1777
|
await connection.hDel(finalKey, finalFields);
|
|
@@ -1754,7 +1781,7 @@ Redis.prototype.hdel = async function(key, fields) {
|
|
|
1754
1781
|
$.log.error('[Redis] 连接对象不支持hDel操作');
|
|
1755
1782
|
success = false;
|
|
1756
1783
|
}
|
|
1757
|
-
|
|
1784
|
+
|
|
1758
1785
|
// 触发后置事件
|
|
1759
1786
|
this.emit('hdel_after', { key: finalKey, value: finalFields, success });
|
|
1760
1787
|
return success;
|
|
@@ -1775,7 +1802,7 @@ Redis.prototype.hdel = async function(key, fields) {
|
|
|
1775
1802
|
* @param {String} field 字段名
|
|
1776
1803
|
* @return {Promise<Boolean>} 是否存在
|
|
1777
1804
|
*/
|
|
1778
|
-
Redis.prototype.hexists = async function(key, field) {
|
|
1805
|
+
Redis.prototype.hexists = async function (key, field) {
|
|
1779
1806
|
try {
|
|
1780
1807
|
const connection = await this._getConnection();
|
|
1781
1808
|
try {
|
|
@@ -1795,7 +1822,7 @@ Redis.prototype.hexists = async function(key, field) {
|
|
|
1795
1822
|
* @param {String} key 键
|
|
1796
1823
|
* @return {Promise<Number>} 字段数量
|
|
1797
1824
|
*/
|
|
1798
|
-
Redis.prototype.hlen = async function(key) {
|
|
1825
|
+
Redis.prototype.hlen = async function (key) {
|
|
1799
1826
|
try {
|
|
1800
1827
|
const connection = await this._getConnection();
|
|
1801
1828
|
try {
|
|
@@ -1876,24 +1903,24 @@ class RedisPipeline {
|
|
|
1876
1903
|
const connection = await this.redis._getConnection();
|
|
1877
1904
|
try {
|
|
1878
1905
|
const pipeline = connection.multi();
|
|
1879
|
-
|
|
1906
|
+
|
|
1880
1907
|
// 执行所有命令
|
|
1881
1908
|
for (const cmd of this.commands) {
|
|
1882
1909
|
const { name, args } = cmd;
|
|
1883
1910
|
let processedArgs = args;
|
|
1884
|
-
|
|
1911
|
+
|
|
1885
1912
|
// 处理键前缀
|
|
1886
1913
|
if (name !== 'multi' && name !== 'exec' && args.length > 0) {
|
|
1887
1914
|
processedArgs = [...args];
|
|
1888
1915
|
// 大多数Redis命令第一个参数是key
|
|
1889
1916
|
processedArgs[0] = this.redis.applyPrefix(args[0]);
|
|
1890
|
-
|
|
1917
|
+
|
|
1891
1918
|
// 对于set命令,处理value的JSON序列化
|
|
1892
|
-
if (name === 'set' && args.length >= 2 && typeof(args[1]) === 'object') {
|
|
1919
|
+
if (name === 'set' && args.length >= 2 && typeof (args[1]) === 'object') {
|
|
1893
1920
|
processedArgs[1] = JSON.stringify(args[1]);
|
|
1894
1921
|
}
|
|
1895
1922
|
}
|
|
1896
|
-
|
|
1923
|
+
|
|
1897
1924
|
// 执行命令
|
|
1898
1925
|
if (name === 'set' && processedArgs.length >= 3) {
|
|
1899
1926
|
// 处理set命令的过期时间
|
|
@@ -1907,21 +1934,21 @@ class RedisPipeline {
|
|
|
1907
1934
|
$.log.warn(`[Redis] Pipeline不支持的命令: ${name}`);
|
|
1908
1935
|
}
|
|
1909
1936
|
}
|
|
1910
|
-
|
|
1937
|
+
|
|
1911
1938
|
// 执行所有命令并获取结果
|
|
1912
1939
|
const results = await pipeline.exec();
|
|
1913
|
-
|
|
1940
|
+
|
|
1914
1941
|
// 处理结果(解析JSON等)
|
|
1915
1942
|
return results.map(([err, value], index) => {
|
|
1916
1943
|
if (err) {
|
|
1917
1944
|
$.log.error(`[Redis] Pipeline命令执行失败 [${this.commands[index].name}]:`, err);
|
|
1918
1945
|
return null;
|
|
1919
1946
|
}
|
|
1920
|
-
|
|
1947
|
+
|
|
1921
1948
|
// 尝试解析JSON结果
|
|
1922
|
-
if (typeof(value) === 'string') {
|
|
1949
|
+
if (typeof (value) === 'string') {
|
|
1923
1950
|
try {
|
|
1924
|
-
if (value.startsWith('{') && value.endsWith('}') ||
|
|
1951
|
+
if (value.startsWith('{') && value.endsWith('}') ||
|
|
1925
1952
|
value.startsWith('[') && value.endsWith(']')) {
|
|
1926
1953
|
return JSON.parse(value);
|
|
1927
1954
|
}
|
|
@@ -1973,237 +2000,75 @@ function redis_admin(scope, dir) {
|
|
|
1973
2000
|
exports.redis_admin = redis_admin;
|
|
1974
2001
|
|
|
1975
2002
|
// 获取连接的方法
|
|
1976
|
-
Redis.prototype._getConnection = function() {
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2003
|
+
Redis.prototype._getConnection = function () {
|
|
2004
|
+
return new Promise((resolve, reject) => {
|
|
2005
|
+
try {
|
|
2006
|
+
// 如果有可用连接,直接返回
|
|
2007
|
+
if (this.connectionPool.available.length > 0) {
|
|
2008
|
+
const connection = this.connectionPool.available.pop();
|
|
2009
|
+
this.connectionPool.inUse.add(connection);
|
|
2010
|
+
resolve(connection);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
// 如果连接数未达到上限,创建新连接
|
|
2015
|
+
const totalConnections = this.connectionPool.available.length + this.connectionPool.inUse.size;
|
|
2016
|
+
if (totalConnections < this.connectionPool.config.max_clients) {
|
|
2017
|
+
this._createConnection().then(connection => {
|
|
2018
|
+
this.connectionPool.inUse.add(connection);
|
|
2019
|
+
resolve(connection);
|
|
2020
|
+
}).catch(reject);
|
|
2021
|
+
} else {
|
|
2022
|
+
// 否则等待连接释放
|
|
2023
|
+
// 这里简化处理,直接创建连接(生产环境应实现等待队列)
|
|
2024
|
+
$.log.warn('[Redis] 连接池已满,创建额外连接');
|
|
2025
|
+
this._createConnection().then(connection => {
|
|
2026
|
+
this.connectionPool.inUse.add(connection);
|
|
2027
|
+
resolve(connection);
|
|
2028
|
+
}).catch(reject);
|
|
2029
|
+
}
|
|
2030
|
+
} catch (error) {
|
|
2031
|
+
$.log.error('[Redis] 获取连接失败:', error);
|
|
2032
|
+
reject(error);
|
|
2033
|
+
}
|
|
2034
|
+
});
|
|
2008
2035
|
};
|
|
2009
2036
|
|
|
2010
2037
|
// 导出Redis类和redis_admin函数
|
|
2011
2038
|
module.exports = {
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
};
|
|
2015
|
-
|
|
2016
|
-
// 创建新连接的方法
|
|
2017
|
-
Redis.prototype._createConnection = function() {
|
|
2018
|
-
return new Promise((resolve, reject) => {
|
|
2019
|
-
try {
|
|
2020
|
-
// 使用原生Redis客户端或模拟连接
|
|
2021
|
-
// 这里创建一个带内存存储的模拟连接对象
|
|
2022
|
-
const memoryStore = new Map();
|
|
2023
|
-
const hashStore = new Map();
|
|
2024
|
-
|
|
2025
|
-
const connection = {
|
|
2026
|
-
id: Date.now() + Math.random(),
|
|
2027
|
-
// 修改execute方法,正确处理参数
|
|
2028
|
-
execute: async (command, ...args) => {
|
|
2029
|
-
$.log.debug(`[Redis] 执行命令: ${command}`, args);
|
|
2030
|
-
|
|
2031
|
-
// 修复参数处理,确保正确解析命令参数
|
|
2032
|
-
let key, field, value;
|
|
2033
|
-
|
|
2034
|
-
switch (command.toLowerCase()) {
|
|
2035
|
-
case 'set':
|
|
2036
|
-
// 确保参数正确解析
|
|
2037
|
-
key = args[0];
|
|
2038
|
-
value = args[1];
|
|
2039
|
-
memoryStore.set(key, value);
|
|
2040
|
-
return 'OK';
|
|
2041
|
-
case 'get':
|
|
2042
|
-
key = args[0];
|
|
2043
|
-
return memoryStore.get(key) || null;
|
|
2044
|
-
case 'del':
|
|
2045
|
-
key = args[0];
|
|
2046
|
-
return memoryStore.delete(key) ? 1 : 0;
|
|
2047
|
-
case 'exists':
|
|
2048
|
-
case 'has':
|
|
2049
|
-
key = args[0];
|
|
2050
|
-
return memoryStore.has(key) ? 1 : 0;
|
|
2051
|
-
case 'hset':
|
|
2052
|
-
// 确保正确解析哈希参数
|
|
2053
|
-
key = args[0];
|
|
2054
|
-
field = args[1];
|
|
2055
|
-
value = args[2];
|
|
2056
|
-
|
|
2057
|
-
if (!hashStore.has(key)) {
|
|
2058
|
-
hashStore.set(key, new Map());
|
|
2059
|
-
}
|
|
2060
|
-
const hash = hashStore.get(key);
|
|
2061
|
-
hash.set(field, value);
|
|
2062
|
-
return 1; // 返回影响的字段数
|
|
2063
|
-
case 'hget':
|
|
2064
|
-
key = args[0];
|
|
2065
|
-
field = args[1];
|
|
2066
|
-
|
|
2067
|
-
const targetHash = hashStore.get(key);
|
|
2068
|
-
if (targetHash && targetHash.has(field)) {
|
|
2069
|
-
return targetHash.get(field);
|
|
2070
|
-
}
|
|
2071
|
-
return null;
|
|
2072
|
-
case 'hgetall':
|
|
2073
|
-
key = args[0];
|
|
2074
|
-
const hashObj = hashStore.get(key);
|
|
2075
|
-
if (!hashObj) return {};
|
|
2076
|
-
|
|
2077
|
-
// 转换Map为普通对象
|
|
2078
|
-
const result = {};
|
|
2079
|
-
for (const [field, value] of hashObj.entries()) {
|
|
2080
|
-
result[field] = value;
|
|
2081
|
-
}
|
|
2082
|
-
return result;
|
|
2083
|
-
case 'hkeys':
|
|
2084
|
-
key = args[0];
|
|
2085
|
-
const targetHashKeys = hashStore.get(key);
|
|
2086
|
-
if (!targetHashKeys) return [];
|
|
2087
|
-
return Array.from(targetHashKeys.keys());
|
|
2088
|
-
case 'hvals':
|
|
2089
|
-
key = args[0];
|
|
2090
|
-
const targetHashVals = hashStore.get(key);
|
|
2091
|
-
if (!targetHashVals) return [];
|
|
2092
|
-
return Array.from(targetHashVals.values());
|
|
2093
|
-
default:
|
|
2094
|
-
return 'OK';
|
|
2095
|
-
}
|
|
2096
|
-
},
|
|
2097
|
-
// 支持Redis客户端的直接方法调用
|
|
2098
|
-
set: async (key, value, options) => {
|
|
2099
|
-
memoryStore.set(key, value);
|
|
2100
|
-
return 'OK';
|
|
2101
|
-
},
|
|
2102
|
-
get: async (key) => {
|
|
2103
|
-
return memoryStore.get(key) || null;
|
|
2104
|
-
},
|
|
2105
|
-
del: async (key) => {
|
|
2106
|
-
return memoryStore.delete(key) ? 1 : 0;
|
|
2107
|
-
},
|
|
2108
|
-
exists: async (key) => {
|
|
2109
|
-
return memoryStore.has(key) ? 1 : 0;
|
|
2110
|
-
},
|
|
2111
|
-
hSet: async (key, field, value) => {
|
|
2112
|
-
if (!hashStore.has(key)) {
|
|
2113
|
-
hashStore.set(key, new Map());
|
|
2114
|
-
}
|
|
2115
|
-
const hash = hashStore.get(key);
|
|
2116
|
-
hash.set(field, value);
|
|
2117
|
-
return 1;
|
|
2118
|
-
},
|
|
2119
|
-
hGet: async (key, field) => {
|
|
2120
|
-
const targetHash = hashStore.get(key);
|
|
2121
|
-
if (targetHash && targetHash.has(field)) {
|
|
2122
|
-
return targetHash.get(field);
|
|
2123
|
-
}
|
|
2124
|
-
return null;
|
|
2125
|
-
},
|
|
2126
|
-
multi: function() {
|
|
2127
|
-
// 返回简单的pipeline实现
|
|
2128
|
-
return {
|
|
2129
|
-
commands: [],
|
|
2130
|
-
set: function(key, value, options) {
|
|
2131
|
-
this.commands.push(['set', key, value, options]);
|
|
2132
|
-
return this;
|
|
2133
|
-
},
|
|
2134
|
-
get: function(key) {
|
|
2135
|
-
this.commands.push(['get', key]);
|
|
2136
|
-
return this;
|
|
2137
|
-
},
|
|
2138
|
-
expire: function(key, seconds) {
|
|
2139
|
-
this.commands.push(['expire', key, seconds]);
|
|
2140
|
-
return this;
|
|
2141
|
-
},
|
|
2142
|
-
exec: async function() {
|
|
2143
|
-
// 实际执行pipeline中的命令
|
|
2144
|
-
const results = [];
|
|
2145
|
-
for (const cmd of this.commands) {
|
|
2146
|
-
try {
|
|
2147
|
-
let result;
|
|
2148
|
-
const [command, ...args] = cmd;
|
|
2149
|
-
|
|
2150
|
-
switch(command) {
|
|
2151
|
-
case 'set':
|
|
2152
|
-
memoryStore.set(args[0], args[1]);
|
|
2153
|
-
result = 'OK';
|
|
2154
|
-
break;
|
|
2155
|
-
case 'get':
|
|
2156
|
-
result = memoryStore.get(args[0]) || null;
|
|
2157
|
-
break;
|
|
2158
|
-
case 'expire':
|
|
2159
|
-
// 简化处理过期时间
|
|
2160
|
-
result = 1;
|
|
2161
|
-
break;
|
|
2162
|
-
default:
|
|
2163
|
-
result = 'OK';
|
|
2164
|
-
}
|
|
2165
|
-
results.push([null, result]);
|
|
2166
|
-
} catch (err) {
|
|
2167
|
-
results.push([err, null]);
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
return results;
|
|
2171
|
-
}
|
|
2172
|
-
};
|
|
2173
|
-
},
|
|
2174
|
-
close: () => {
|
|
2175
|
-
$.log.debug('[Redis] 关闭连接');
|
|
2176
|
-
}
|
|
2177
|
-
};
|
|
2178
|
-
|
|
2179
|
-
$.log.debug('[Redis] 新连接已创建:', connection.id);
|
|
2180
|
-
resolve(connection);
|
|
2181
|
-
} catch (error) {
|
|
2182
|
-
$.log.error('[Redis] 创建连接失败:', error);
|
|
2183
|
-
reject(error);
|
|
2184
|
-
}
|
|
2185
|
-
});
|
|
2039
|
+
Redis: Redis,
|
|
2040
|
+
redis_admin: redis_admin
|
|
2186
2041
|
};
|
|
2187
2042
|
|
|
2188
2043
|
// 释放连接回池
|
|
2189
|
-
Redis.prototype._releaseConnection = function(connection) {
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2044
|
+
Redis.prototype._releaseConnection = function (connection) {
|
|
2045
|
+
try {
|
|
2046
|
+
if (this.connectionPool.inUse.has(connection)) {
|
|
2047
|
+
this.connectionPool.inUse.delete(connection);
|
|
2048
|
+
|
|
2049
|
+
// 检查是否超过最大空闲连接数
|
|
2050
|
+
if (this.connectionPool.available.length < this.connectionPool.config.max_idle) {
|
|
2051
|
+
this.connectionPool.available.push(connection);
|
|
2052
|
+
$.log.debug('[Redis] 连接已释放回池中:', connection.id);
|
|
2053
|
+
} else {
|
|
2054
|
+
// 否则关闭多余的连接
|
|
2055
|
+
try {
|
|
2056
|
+
if (typeof connection.close === 'function') {
|
|
2057
|
+
connection.close();
|
|
2058
|
+
} else if (typeof connection.end === 'function') {
|
|
2059
|
+
connection.end();
|
|
2060
|
+
} else {
|
|
2061
|
+
$.log.debug('[Redis] 连接对象没有可用的关闭方法');
|
|
2062
|
+
}
|
|
2063
|
+
$.log.debug('[Redis] 关闭多余连接:', connection.id);
|
|
2064
|
+
} catch (e) {
|
|
2065
|
+
$.log.error('[Redis] 关闭多余连接失败:', e);
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
2069
|
+
} catch (error) {
|
|
2070
|
+
$.log.error('[Redis] 释放连接失败:', error);
|
|
2071
|
+
}
|
|
2207
2072
|
};
|
|
2208
2073
|
|
|
2209
2074
|
// 添加Hash操作相关方法
|
|
@@ -2215,43 +2080,43 @@ Redis.prototype._releaseConnection = function(connection) {
|
|
|
2215
2080
|
* @param {Object} value 值
|
|
2216
2081
|
* @return {Promise<Boolean>} 操作结果
|
|
2217
2082
|
*/
|
|
2218
|
-
Redis.prototype.hset = async function(key, field, value) {
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2083
|
+
Redis.prototype.hset = async function (key, field, value) {
|
|
2084
|
+
try {
|
|
2085
|
+
// 触发前置事件,允许修改或阻止操作
|
|
2086
|
+
const beforeEventData = { key, field, value, cancel: false };
|
|
2087
|
+
this.emit('hset_before', beforeEventData);
|
|
2088
|
+
|
|
2089
|
+
// 如果事件处理器标记为取消,则返回false
|
|
2090
|
+
if (beforeEventData.cancel) {
|
|
2091
|
+
$.log.debug(`[Redis] hset操作被事件处理器取消 [${key}:${field}]`);
|
|
2092
|
+
return false;
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
// 使用可能被修改的值
|
|
2096
|
+
let { key: finalKey, field: finalField, value: finalValue } = beforeEventData;
|
|
2097
|
+
|
|
2098
|
+
const connection = await this._getConnection();
|
|
2099
|
+
try {
|
|
2100
|
+
finalKey = this.applyPrefix(finalKey);
|
|
2101
|
+
// 确保所有非字符串值都转换为字符串
|
|
2102
|
+
if (typeof (finalValue) !== "string") {
|
|
2103
|
+
finalValue = JSON.stringify(finalValue);
|
|
2104
|
+
}
|
|
2105
|
+
// 使用正确的Redis v4 API - hSet方法
|
|
2106
|
+
const result = await connection.hSet(finalKey, finalField, finalValue);
|
|
2107
|
+
|
|
2108
|
+
// 触发后置事件
|
|
2109
|
+
this.emit('hset_after', { key: finalKey, field: finalField, value: finalValue, success: true });
|
|
2110
|
+
return result > 0; // 如果field是新的,hSet返回1,否则返回0
|
|
2111
|
+
} finally {
|
|
2112
|
+
this._recycleConnection(connection);
|
|
2113
|
+
}
|
|
2114
|
+
} catch (err) {
|
|
2115
|
+
$.log.error(`[Redis] 设置哈希字段失败 [${key}:${field}]:`, err);
|
|
2116
|
+
// 触发错误事件
|
|
2117
|
+
this.emit('hset_error', { key, field, value, error: err });
|
|
2118
|
+
return false;
|
|
2119
|
+
}
|
|
2255
2120
|
};
|
|
2256
2121
|
|
|
2257
2122
|
/**
|
|
@@ -2260,33 +2125,33 @@ Redis.prototype.hset = async function(key, field, value) {
|
|
|
2260
2125
|
* @param {String} field 字段
|
|
2261
2126
|
* @return {Promise<Object>} 字段值
|
|
2262
2127
|
*/
|
|
2263
|
-
Redis.prototype.hget = async function(key, field) {
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2128
|
+
Redis.prototype.hget = async function (key, field) {
|
|
2129
|
+
try {
|
|
2130
|
+
const connection = await this._getConnection();
|
|
2131
|
+
try {
|
|
2132
|
+
key = this.applyPrefix(key);
|
|
2133
|
+
// 使用正确的Redis v4 API - hGet方法
|
|
2134
|
+
const value = await connection.hGet(key, field);
|
|
2135
|
+
// 尝试解析JSON
|
|
2136
|
+
if (value && typeof (value) === 'string') {
|
|
2137
|
+
try {
|
|
2138
|
+
if (value.startsWith('{') && value.endsWith('}') ||
|
|
2139
|
+
value.startsWith('[') && value.endsWith(']')) {
|
|
2140
|
+
return JSON.parse(value);
|
|
2141
|
+
}
|
|
2142
|
+
} catch (e) {
|
|
2143
|
+
// 如果不是JSON,直接返回原值
|
|
2144
|
+
return value;
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
return value;
|
|
2148
|
+
} finally {
|
|
2149
|
+
this._recycleConnection(connection);
|
|
2150
|
+
}
|
|
2151
|
+
} catch (err) {
|
|
2152
|
+
$.log.error(`[Redis] 获取哈希字段失败 [${key}:${field}]:`, err);
|
|
2153
|
+
return null;
|
|
2154
|
+
}
|
|
2290
2155
|
};
|
|
2291
2156
|
|
|
2292
2157
|
/**
|
|
@@ -2295,49 +2160,49 @@ Redis.prototype.hget = async function(key, field) {
|
|
|
2295
2160
|
* @param {Object} obj 字段值对象
|
|
2296
2161
|
* @return {Promise<Boolean>} 操作结果
|
|
2297
2162
|
*/
|
|
2298
|
-
Redis.prototype.hmset = async function(key, obj) {
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2163
|
+
Redis.prototype.hmset = async function (key, obj) {
|
|
2164
|
+
try {
|
|
2165
|
+
// 触发前置事件,允许修改或阻止操作
|
|
2166
|
+
const beforeEventData = { key, value: obj, cancel: false };
|
|
2167
|
+
this.emit('hmset_before', beforeEventData);
|
|
2168
|
+
|
|
2169
|
+
// 如果事件处理器标记为取消,则返回false
|
|
2170
|
+
if (beforeEventData.cancel) {
|
|
2171
|
+
$.log.debug(`[Redis] hmset操作被事件处理器取消 [${key}]`);
|
|
2172
|
+
return false;
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
// 使用可能被修改的值
|
|
2176
|
+
let { key: finalKey, value: finalObj } = beforeEventData;
|
|
2177
|
+
|
|
2178
|
+
const connection = await this._getConnection();
|
|
2179
|
+
try {
|
|
2180
|
+
finalKey = this.applyPrefix(finalKey);
|
|
2181
|
+
|
|
2182
|
+
// 为每个字段设置值
|
|
2183
|
+
for (const field in finalObj) {
|
|
2184
|
+
if (finalObj.hasOwnProperty(field)) {
|
|
2185
|
+
let value = finalObj[field];
|
|
2186
|
+
// 确保值是字符串类型
|
|
2187
|
+
if (typeof value !== 'string') {
|
|
2188
|
+
value = JSON.stringify(value);
|
|
2189
|
+
}
|
|
2190
|
+
await connection.execute('hset', finalKey, field, value);
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
|
|
2194
|
+
// 触发后置事件
|
|
2195
|
+
this.emit('hmset_after', { key: finalKey, value: finalObj, success: true });
|
|
2196
|
+
return true;
|
|
2197
|
+
} finally {
|
|
2198
|
+
this._recycleConnection(connection);
|
|
2199
|
+
}
|
|
2200
|
+
} catch (err) {
|
|
2201
|
+
$.log.error(`[Redis] 批量设置哈希字段失败 [${key}]:`, err);
|
|
2202
|
+
// 触发错误事件
|
|
2203
|
+
this.emit('hmset_error', { key, value: obj, error: err });
|
|
2204
|
+
return false;
|
|
2205
|
+
}
|
|
2341
2206
|
};
|
|
2342
2207
|
|
|
2343
2208
|
/**
|
|
@@ -2345,74 +2210,74 @@ Redis.prototype.hmset = async function(key, obj) {
|
|
|
2345
2210
|
* @param {String} key 键
|
|
2346
2211
|
* @return {Promise<Object>} 所有字段和值
|
|
2347
2212
|
*/
|
|
2348
|
-
Redis.prototype.hgetall = async function(key) {
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
};
|
|
2363
|
-
|
|
2364
|
-
/**
|
|
2365
|
-
* @description 获取哈希的字段名
|
|
2366
|
-
* @param {String} key 键
|
|
2367
|
-
* @return {Promise<Array>} 字段名数组
|
|
2368
|
-
*/
|
|
2369
|
-
Redis.prototype.hkeys = async function(key) {
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
};
|
|
2383
|
-
|
|
2213
|
+
Redis.prototype.hgetall = async function (key) {
|
|
2214
|
+
try {
|
|
2215
|
+
const connection = await this._getConnection();
|
|
2216
|
+
try {
|
|
2217
|
+
key = this.applyPrefix(key);
|
|
2218
|
+
const result = await connection.execute('hgetall', key);
|
|
2219
|
+
return result;
|
|
2220
|
+
} finally {
|
|
2221
|
+
this._releaseConnection(connection);
|
|
2222
|
+
}
|
|
2223
|
+
} catch (err) {
|
|
2224
|
+
$.log.error(`[Redis] 获取哈希所有字段和值失败 [${key}]:`, err);
|
|
2225
|
+
return null;
|
|
2226
|
+
}
|
|
2227
|
+
};
|
|
2228
|
+
|
|
2229
|
+
/**
|
|
2230
|
+
* @description 获取哈希的字段名
|
|
2231
|
+
* @param {String} key 键
|
|
2232
|
+
* @return {Promise<Array>} 字段名数组
|
|
2233
|
+
*/
|
|
2234
|
+
Redis.prototype.hkeys = async function (key) {
|
|
2235
|
+
try {
|
|
2236
|
+
const connection = await this._getConnection();
|
|
2237
|
+
try {
|
|
2238
|
+
key = this.applyPrefix(key);
|
|
2239
|
+
return await connection.execute('hkeys', key);
|
|
2240
|
+
} finally {
|
|
2241
|
+
this._releaseConnection(connection);
|
|
2242
|
+
}
|
|
2243
|
+
} catch (err) {
|
|
2244
|
+
$.log.error(`[Redis] 获取哈希字段名失败 [${key}]:`, err);
|
|
2245
|
+
return [];
|
|
2246
|
+
}
|
|
2247
|
+
};
|
|
2248
|
+
|
|
2384
2249
|
/**
|
|
2385
2250
|
* @description 获取哈希的字段值
|
|
2386
2251
|
* @param {String} key 键
|
|
2387
2252
|
* @return {Promise<Array>} 字段值数组
|
|
2388
2253
|
*/
|
|
2389
|
-
Redis.prototype.hvals = async function(key) {
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2254
|
+
Redis.prototype.hvals = async function (key) {
|
|
2255
|
+
try {
|
|
2256
|
+
const connection = await this._getConnection();
|
|
2257
|
+
try {
|
|
2258
|
+
key = this.applyPrefix(key);
|
|
2259
|
+
const values = await connection.execute('hvals', key);
|
|
2260
|
+
// 尝试解析每个值为JSON
|
|
2261
|
+
return values.map(value => {
|
|
2262
|
+
if (typeof (value) === "string") {
|
|
2263
|
+
try {
|
|
2264
|
+
if (value.startsWith("{") && value.endsWith("}") ||
|
|
2265
|
+
value.startsWith("[") && value.endsWith("]")) {
|
|
2266
|
+
return JSON.parse(value);
|
|
2267
|
+
}
|
|
2268
|
+
} catch (e) {
|
|
2269
|
+
// 解析失败,返回原始字符串
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
return value;
|
|
2273
|
+
});
|
|
2274
|
+
} finally {
|
|
2275
|
+
this._releaseConnection(connection);
|
|
2276
|
+
}
|
|
2277
|
+
} catch (err) {
|
|
2278
|
+
$.log.error(`[Redis] 获取哈希字段值数组失败 [${key}]:`, err);
|
|
2279
|
+
return [];
|
|
2280
|
+
}
|
|
2416
2281
|
};
|
|
2417
2282
|
|
|
2418
2283
|
/**
|
|
@@ -2421,34 +2286,34 @@ Redis.prototype.hvals = async function(key) {
|
|
|
2421
2286
|
* @param {Number} seconds 过期时间(秒)
|
|
2422
2287
|
* @return {Promise<Boolean>} 操作结果
|
|
2423
2288
|
*/
|
|
2424
|
-
Redis.prototype.expire = async function(key, seconds) {
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2442
|
-
|
|
2443
|
-
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2289
|
+
Redis.prototype.expire = async function (key, seconds) {
|
|
2290
|
+
try {
|
|
2291
|
+
// 触发前置事件
|
|
2292
|
+
const beforeEventData = { key, ttl: seconds, cancel: false };
|
|
2293
|
+
this.emit('expire_before', beforeEventData);
|
|
2294
|
+
|
|
2295
|
+
if (beforeEventData.cancel) {
|
|
2296
|
+
$.log.debug(`[Redis] expire操作被事件处理器取消 [${key}]`);
|
|
2297
|
+
return false;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
const { key: finalKey, ttl: finalSeconds } = beforeEventData;
|
|
2301
|
+
|
|
2302
|
+
const connection = await this._getConnection();
|
|
2303
|
+
try {
|
|
2304
|
+
const result = await connection.execute('expire', this.applyPrefix(finalKey), finalSeconds);
|
|
2305
|
+
|
|
2306
|
+
// 触发后置事件
|
|
2307
|
+
this.emit('expire_after', { key: finalKey, ttl: finalSeconds, success: result === 1 });
|
|
2308
|
+
return result === 1;
|
|
2309
|
+
} finally {
|
|
2310
|
+
this._recycleConnection(connection);
|
|
2311
|
+
}
|
|
2312
|
+
} catch (err) {
|
|
2313
|
+
$.log.error(`[Redis] 设置过期时间失败 [${key}]:`, err);
|
|
2314
|
+
this.emit('expire_error', { key, ttl: seconds, error: err });
|
|
2315
|
+
return false;
|
|
2316
|
+
}
|
|
2452
2317
|
};
|
|
2453
2318
|
|
|
2454
2319
|
/**
|
|
@@ -2456,21 +2321,32 @@ Redis.prototype.expire = async function(key, seconds) {
|
|
|
2456
2321
|
* @param {String} key 键
|
|
2457
2322
|
* @return {Promise<Number>} 增加后的值
|
|
2458
2323
|
*/
|
|
2459
|
-
Redis.prototype.incr = async function(key) {
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
|
|
2324
|
+
Redis.prototype.incr = async function (key) {
|
|
2325
|
+
try {
|
|
2326
|
+
// 触发前置事件
|
|
2327
|
+
const beforeEventData = { key, cancel: false };
|
|
2328
|
+
this.emit('incr_before', beforeEventData);
|
|
2329
|
+
|
|
2330
|
+
if (beforeEventData.cancel) {
|
|
2331
|
+
$.log.debug(`[Redis] incr操作被事件处理器取消 [${key}]`);
|
|
2332
|
+
return null;
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2335
|
+
const { key: finalKey } = beforeEventData;
|
|
2336
|
+
|
|
2337
|
+
const connection = await this._getConnection();
|
|
2338
|
+
try {
|
|
2339
|
+
const result = await connection.execute('incr', this.applyPrefix(finalKey));
|
|
2340
|
+
this.emit('incr_after', { key: finalKey, result });
|
|
2341
|
+
return result;
|
|
2342
|
+
} finally {
|
|
2343
|
+
this._recycleConnection(connection);
|
|
2344
|
+
}
|
|
2345
|
+
} catch (err) {
|
|
2346
|
+
$.log.error(`[Redis] 增加整数值失败 [${key}]:`, err);
|
|
2347
|
+
this.emit('incr_error', { key, error: err });
|
|
2348
|
+
return null;
|
|
2349
|
+
}
|
|
2474
2350
|
};
|
|
2475
2351
|
|
|
2476
2352
|
/**
|
|
@@ -2478,21 +2354,32 @@ Redis.prototype.incr = async function(key) {
|
|
|
2478
2354
|
* @param {String} key 键
|
|
2479
2355
|
* @return {Promise<Number>} 减少后的值
|
|
2480
2356
|
*/
|
|
2481
|
-
Redis.prototype.decr = async function(key) {
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2357
|
+
Redis.prototype.decr = async function (key) {
|
|
2358
|
+
try {
|
|
2359
|
+
// 触发前置事件
|
|
2360
|
+
const beforeEventData = { key, cancel: false };
|
|
2361
|
+
this.emit('decr_before', beforeEventData);
|
|
2362
|
+
|
|
2363
|
+
if (beforeEventData.cancel) {
|
|
2364
|
+
$.log.debug(`[Redis] decr操作被事件处理器取消 [${key}]`);
|
|
2365
|
+
return null;
|
|
2366
|
+
}
|
|
2367
|
+
|
|
2368
|
+
const { key: finalKey } = beforeEventData;
|
|
2369
|
+
|
|
2370
|
+
const connection = await this._getConnection();
|
|
2371
|
+
try {
|
|
2372
|
+
const result = await connection.execute('decr', this.applyPrefix(finalKey));
|
|
2373
|
+
this.emit('decr_after', { key: finalKey, result });
|
|
2374
|
+
return result;
|
|
2375
|
+
} finally {
|
|
2376
|
+
this._recycleConnection(connection);
|
|
2377
|
+
}
|
|
2378
|
+
} catch (err) {
|
|
2379
|
+
$.log.error(`[Redis] 减少整数值失败 [${key}]:`, err);
|
|
2380
|
+
this.emit('decr_error', { key, error: err });
|
|
2381
|
+
return null;
|
|
2382
|
+
}
|
|
2496
2383
|
};
|
|
2497
2384
|
|
|
2498
2385
|
/**
|
|
@@ -2501,21 +2388,32 @@ Redis.prototype.decr = async function(key) {
|
|
|
2501
2388
|
* @param {Number} increment 增量
|
|
2502
2389
|
* @return {Promise<Number>} 增加后的值
|
|
2503
2390
|
*/
|
|
2504
|
-
Redis.prototype.incrby = async function(key, increment) {
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2391
|
+
Redis.prototype.incrby = async function (key, increment) {
|
|
2392
|
+
try {
|
|
2393
|
+
// 触发前置事件
|
|
2394
|
+
const beforeEventData = { key, increment, cancel: false };
|
|
2395
|
+
this.emit('incrby_before', beforeEventData);
|
|
2396
|
+
|
|
2397
|
+
if (beforeEventData.cancel) {
|
|
2398
|
+
$.log.debug(`[Redis] incrby操作被事件处理器取消 [${key}]`);
|
|
2399
|
+
return null;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
const { key: finalKey, increment: finalIncrement } = beforeEventData;
|
|
2403
|
+
|
|
2404
|
+
const connection = await this._getConnection();
|
|
2405
|
+
try {
|
|
2406
|
+
const result = await connection.execute('incrby', this.applyPrefix(finalKey), finalIncrement);
|
|
2407
|
+
this.emit('incrby_after', { key: finalKey, increment: finalIncrement, result });
|
|
2408
|
+
return result;
|
|
2409
|
+
} finally {
|
|
2410
|
+
this._recycleConnection(connection);
|
|
2411
|
+
}
|
|
2412
|
+
} catch (err) {
|
|
2413
|
+
$.log.error(`[Redis] 增加指定值失败 [${key}]:`, err);
|
|
2414
|
+
this.emit('incrby_error', { key, increment, error: err });
|
|
2415
|
+
return null;
|
|
2416
|
+
}
|
|
2519
2417
|
};
|
|
2520
2418
|
|
|
2521
2419
|
/**
|
|
@@ -2524,21 +2422,32 @@ Redis.prototype.incrby = async function(key, increment) {
|
|
|
2524
2422
|
* @param {Number} decrement 减量
|
|
2525
2423
|
* @return {Promise<Number>} 减少后的值
|
|
2526
2424
|
*/
|
|
2527
|
-
Redis.prototype.decrby = async function(key, decrement) {
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2425
|
+
Redis.prototype.decrby = async function (key, decrement) {
|
|
2426
|
+
try {
|
|
2427
|
+
// 触发前置事件
|
|
2428
|
+
const beforeEventData = { key, decrement, cancel: false };
|
|
2429
|
+
this.emit('decrby_before', beforeEventData);
|
|
2430
|
+
|
|
2431
|
+
if (beforeEventData.cancel) {
|
|
2432
|
+
$.log.debug(`[Redis] decrby操作被事件处理器取消 [${key}]`);
|
|
2433
|
+
return null;
|
|
2434
|
+
}
|
|
2435
|
+
|
|
2436
|
+
const { key: finalKey, decrement: finalDecrement } = beforeEventData;
|
|
2437
|
+
|
|
2438
|
+
const connection = await this._getConnection();
|
|
2439
|
+
try {
|
|
2440
|
+
const result = await connection.execute('decrby', this.applyPrefix(finalKey), finalDecrement);
|
|
2441
|
+
this.emit('decrby_after', { key: finalKey, decrement: finalDecrement, result });
|
|
2442
|
+
return result;
|
|
2443
|
+
} finally {
|
|
2444
|
+
this._recycleConnection(connection);
|
|
2445
|
+
}
|
|
2446
|
+
} catch (err) {
|
|
2447
|
+
$.log.error(`[Redis] 减少指定值失败 [${key}]:`, err);
|
|
2448
|
+
this.emit('decrby_error', { key, decrement, error: err });
|
|
2449
|
+
return null;
|
|
2450
|
+
}
|
|
2542
2451
|
};
|
|
2543
2452
|
|
|
2544
2453
|
// 集合操作方法
|
|
@@ -2549,35 +2458,35 @@ Redis.prototype.decrby = async function(key, decrement) {
|
|
|
2549
2458
|
* @param {String|Array} members 成员或成员数组
|
|
2550
2459
|
* @return {Promise<Number>} 添加的成员数量
|
|
2551
2460
|
*/
|
|
2552
|
-
Redis.prototype.sadd = async function(key, members) {
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2461
|
+
Redis.prototype.sadd = async function (key, members) {
|
|
2462
|
+
try {
|
|
2463
|
+
// 触发前置事件
|
|
2464
|
+
const beforeEventData = { key, members: Array.isArray(members) ? members : [members], cancel: false };
|
|
2465
|
+
this.emit('sadd_before', beforeEventData);
|
|
2466
|
+
|
|
2467
|
+
if (beforeEventData.cancel) {
|
|
2468
|
+
$.log.debug(`[Redis] sadd操作被事件处理器取消 [${key}]`);
|
|
2469
|
+
return 0;
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
const { key: finalKey, members: finalMembers } = beforeEventData;
|
|
2473
|
+
|
|
2474
|
+
const connection = await this._getConnection();
|
|
2475
|
+
try {
|
|
2476
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2477
|
+
const result = await connection.sAdd(prefixedKey, finalMembers);
|
|
2478
|
+
|
|
2479
|
+
// 触发后置事件
|
|
2480
|
+
this.emit('sadd_after', { key: finalKey, members: finalMembers, result });
|
|
2481
|
+
return result;
|
|
2482
|
+
} finally {
|
|
2483
|
+
this._recycleConnection(connection);
|
|
2484
|
+
}
|
|
2485
|
+
} catch (err) {
|
|
2486
|
+
$.log.error(`[Redis] 添加集合成员失败 [${key}]:`, err);
|
|
2487
|
+
this.emit('sadd_error', { key, members, error: err });
|
|
2488
|
+
return 0;
|
|
2489
|
+
}
|
|
2581
2490
|
};
|
|
2582
2491
|
|
|
2583
2492
|
/**
|
|
@@ -2586,35 +2495,35 @@ Redis.prototype.sadd = async function(key, members) {
|
|
|
2586
2495
|
* @param {String|Array} members 成员或成员数组
|
|
2587
2496
|
* @return {Promise<Number>} 移除的成员数量
|
|
2588
2497
|
*/
|
|
2589
|
-
Redis.prototype.srem = async function(key, members) {
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2498
|
+
Redis.prototype.srem = async function (key, members) {
|
|
2499
|
+
try {
|
|
2500
|
+
// 触发前置事件
|
|
2501
|
+
const beforeEventData = { key, members: Array.isArray(members) ? members : [members], cancel: false };
|
|
2502
|
+
this.emit('srem_before', beforeEventData);
|
|
2503
|
+
|
|
2504
|
+
if (beforeEventData.cancel) {
|
|
2505
|
+
$.log.debug(`[Redis] srem操作被事件处理器取消 [${key}]`);
|
|
2506
|
+
return 0;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
const { key: finalKey, members: finalMembers } = beforeEventData;
|
|
2510
|
+
|
|
2511
|
+
const connection = await this._getConnection();
|
|
2512
|
+
try {
|
|
2513
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2514
|
+
const result = await connection.sRem(prefixedKey, finalMembers);
|
|
2515
|
+
|
|
2516
|
+
// 触发后置事件
|
|
2517
|
+
this.emit('srem_after', { key: finalKey, members: finalMembers, result });
|
|
2518
|
+
return result;
|
|
2519
|
+
} finally {
|
|
2520
|
+
this._recycleConnection(connection);
|
|
2521
|
+
}
|
|
2522
|
+
} catch (err) {
|
|
2523
|
+
$.log.error(`[Redis] 移除集合成员失败 [${key}]:`, err);
|
|
2524
|
+
this.emit('srem_error', { key, members, error: err });
|
|
2525
|
+
return 0;
|
|
2526
|
+
}
|
|
2618
2527
|
};
|
|
2619
2528
|
|
|
2620
2529
|
/**
|
|
@@ -2623,19 +2532,20 @@ Redis.prototype.srem = async function(key, members) {
|
|
|
2623
2532
|
* @param {String} member 成员
|
|
2624
2533
|
* @return {Promise<Boolean>} 是否存在
|
|
2625
2534
|
*/
|
|
2626
|
-
Redis.prototype.sismember = async function(key, member) {
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2535
|
+
Redis.prototype.sismember = async function (key, member) {
|
|
2536
|
+
try {
|
|
2537
|
+
const connection = await this._getConnection();
|
|
2538
|
+
try {
|
|
2539
|
+
const prefixedKey = this.applyPrefix(key);
|
|
2540
|
+
const result = await connection.sIsMember(prefixedKey, member);
|
|
2541
|
+
return result;
|
|
2542
|
+
} finally {
|
|
2543
|
+
this._recycleConnection(connection);
|
|
2544
|
+
}
|
|
2545
|
+
} catch (err) {
|
|
2546
|
+
$.log.error(`[Redis] 检查集合成员失败 [${key}:${member}]:`, err);
|
|
2547
|
+
return false;
|
|
2548
|
+
}
|
|
2639
2549
|
};
|
|
2640
2550
|
|
|
2641
2551
|
/**
|
|
@@ -2643,21 +2553,22 @@ Redis.prototype.sismember = async function(key, member) {
|
|
|
2643
2553
|
* @param {String} key 键
|
|
2644
2554
|
* @return {Promise<Array>} 成员数组
|
|
2645
2555
|
*/
|
|
2646
|
-
Redis.prototype.smembers = async function(key) {
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2556
|
+
Redis.prototype.smembers = async function (key) {
|
|
2557
|
+
try {
|
|
2558
|
+
const connection = await this._getConnection();
|
|
2559
|
+
try {
|
|
2560
|
+
const prefixedKey = this.applyPrefix(key);
|
|
2561
|
+
const result = await connection.sMembers(prefixedKey);
|
|
2562
|
+
this.emit('smembers_after', { key, result });
|
|
2563
|
+
return result || [];
|
|
2564
|
+
} finally {
|
|
2565
|
+
this._recycleConnection(connection);
|
|
2566
|
+
}
|
|
2567
|
+
} catch (err) {
|
|
2568
|
+
$.log.error(`[Redis] 获取集合所有成员失败 [${key}]:`, err);
|
|
2569
|
+
this.emit('smembers_error', { key, error: err });
|
|
2570
|
+
return [];
|
|
2571
|
+
}
|
|
2661
2572
|
};
|
|
2662
2573
|
|
|
2663
2574
|
/**
|
|
@@ -2665,19 +2576,20 @@ Redis.prototype.smembers = async function(key) {
|
|
|
2665
2576
|
* @param {String} key 键
|
|
2666
2577
|
* @return {Promise<Number>} 成员数量
|
|
2667
2578
|
*/
|
|
2668
|
-
Redis.prototype.scard = async function(key) {
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2579
|
+
Redis.prototype.scard = async function (key) {
|
|
2580
|
+
try {
|
|
2581
|
+
const connection = await this._getConnection();
|
|
2582
|
+
try {
|
|
2583
|
+
const prefixedKey = this.applyPrefix(key);
|
|
2584
|
+
const result = await connection.sCard(prefixedKey);
|
|
2585
|
+
return result;
|
|
2586
|
+
} finally {
|
|
2587
|
+
this._recycleConnection(connection);
|
|
2588
|
+
}
|
|
2589
|
+
} catch (err) {
|
|
2590
|
+
$.log.error(`[Redis] 获取集合大小失败 [${key}]:`, err);
|
|
2591
|
+
return 0;
|
|
2592
|
+
}
|
|
2681
2593
|
};
|
|
2682
2594
|
|
|
2683
2595
|
/**
|
|
@@ -2685,20 +2597,20 @@ Redis.prototype.scard = async function(key) {
|
|
|
2685
2597
|
* @param {Array} keys 键数组
|
|
2686
2598
|
* @return {Promise<Array>} 交集成员数组
|
|
2687
2599
|
*/
|
|
2688
|
-
Redis.prototype.sinter = async function(keys) {
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2600
|
+
Redis.prototype.sinter = async function (keys) {
|
|
2601
|
+
try {
|
|
2602
|
+
const connection = await this._getConnection();
|
|
2603
|
+
try {
|
|
2604
|
+
const prefixedKeys = keys.map(key => this.applyPrefix(key));
|
|
2605
|
+
const result = await connection.execute('sinter', ...prefixedKeys);
|
|
2606
|
+
return result || [];
|
|
2607
|
+
} finally {
|
|
2608
|
+
this._recycleConnection(connection);
|
|
2609
|
+
}
|
|
2610
|
+
} catch (err) {
|
|
2611
|
+
$.log.error(`[Redis] 获取集合交集失败:`, err);
|
|
2612
|
+
return [];
|
|
2613
|
+
}
|
|
2702
2614
|
};
|
|
2703
2615
|
|
|
2704
2616
|
/**
|
|
@@ -2706,20 +2618,20 @@ Redis.prototype.sinter = async function(keys) {
|
|
|
2706
2618
|
* @param {Array} keys 键数组
|
|
2707
2619
|
* @return {Promise<Array>} 并集成员数组
|
|
2708
2620
|
*/
|
|
2709
|
-
Redis.prototype.sunion = async function(keys) {
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2621
|
+
Redis.prototype.sunion = async function (keys) {
|
|
2622
|
+
try {
|
|
2623
|
+
const connection = await this._getConnection();
|
|
2624
|
+
try {
|
|
2625
|
+
const prefixedKeys = keys.map(key => this.applyPrefix(key));
|
|
2626
|
+
const result = await connection.execute('sunion', ...prefixedKeys);
|
|
2627
|
+
return result || [];
|
|
2628
|
+
} finally {
|
|
2629
|
+
this._recycleConnection(connection);
|
|
2630
|
+
}
|
|
2631
|
+
} catch (err) {
|
|
2632
|
+
$.log.error(`[Redis] 获取集合并集失败:`, err);
|
|
2633
|
+
return [];
|
|
2634
|
+
}
|
|
2723
2635
|
};
|
|
2724
2636
|
|
|
2725
2637
|
/**
|
|
@@ -2727,20 +2639,20 @@ Redis.prototype.sunion = async function(keys) {
|
|
|
2727
2639
|
* @param {Array} keys 键数组
|
|
2728
2640
|
* @return {Promise<Array>} 差集成员数组
|
|
2729
2641
|
*/
|
|
2730
|
-
Redis.prototype.sdiff = async function(keys) {
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2642
|
+
Redis.prototype.sdiff = async function (keys) {
|
|
2643
|
+
try {
|
|
2644
|
+
const connection = await this._getConnection();
|
|
2645
|
+
try {
|
|
2646
|
+
const prefixedKeys = keys.map(key => this.applyPrefix(key));
|
|
2647
|
+
const result = await connection.execute('sdiff', ...prefixedKeys);
|
|
2648
|
+
return result || [];
|
|
2649
|
+
} finally {
|
|
2650
|
+
this._recycleConnection(connection);
|
|
2651
|
+
}
|
|
2652
|
+
} catch (err) {
|
|
2653
|
+
$.log.error(`[Redis] 获取集合差集失败:`, err);
|
|
2654
|
+
return [];
|
|
2655
|
+
}
|
|
2744
2656
|
};
|
|
2745
2657
|
|
|
2746
2658
|
// 有序集合操作方法
|
|
@@ -2752,34 +2664,35 @@ Redis.prototype.sdiff = async function(keys) {
|
|
|
2752
2664
|
* @param {String} member 成员
|
|
2753
2665
|
* @return {Promise<Boolean>} 是否成功
|
|
2754
2666
|
*/
|
|
2755
|
-
Redis.prototype.zadd = async function(key, score, member) {
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2667
|
+
Redis.prototype.zadd = async function (key, score, member) {
|
|
2668
|
+
try {
|
|
2669
|
+
// 触发前置事件
|
|
2670
|
+
const beforeEventData = { key, score, member, cancel: false };
|
|
2671
|
+
this.emit('zadd_before', beforeEventData);
|
|
2672
|
+
|
|
2673
|
+
if (beforeEventData.cancel) {
|
|
2674
|
+
$.log.debug(`[Redis] zadd操作被事件处理器取消 [${key}]`);
|
|
2675
|
+
return false;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2678
|
+
const { key: finalKey, score: finalScore, member: finalMember } = beforeEventData;
|
|
2679
|
+
|
|
2680
|
+
const connection = await this._getConnection();
|
|
2681
|
+
try {
|
|
2682
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2683
|
+
const result = await connection.zAdd(prefixedKey, { score: finalScore, value: finalMember });
|
|
2684
|
+
|
|
2685
|
+
// 触发后置事件
|
|
2686
|
+
this.emit('zadd_after', { key: finalKey, score: finalScore, member: finalMember, success: result === 1 });
|
|
2687
|
+
return result === 1;
|
|
2688
|
+
} finally {
|
|
2689
|
+
this._recycleConnection(connection);
|
|
2690
|
+
}
|
|
2691
|
+
} catch (err) {
|
|
2692
|
+
$.log.error(`[Redis] 添加有序集合成员失败 [${key}]:`, err);
|
|
2693
|
+
this.emit('zadd_error', { key, score, member, error: err });
|
|
2694
|
+
return false;
|
|
2695
|
+
}
|
|
2783
2696
|
};
|
|
2784
2697
|
|
|
2785
2698
|
/**
|
|
@@ -2788,35 +2701,35 @@ Redis.prototype.zadd = async function(key, score, member) {
|
|
|
2788
2701
|
* @param {String|Array} members 成员或成员数组
|
|
2789
2702
|
* @return {Promise<Number>} 移除的成员数量
|
|
2790
2703
|
*/
|
|
2791
|
-
Redis.prototype.zrem = async function(key, members) {
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2797
|
-
|
|
2798
|
-
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2704
|
+
Redis.prototype.zrem = async function (key, members) {
|
|
2705
|
+
try {
|
|
2706
|
+
// 触发前置事件
|
|
2707
|
+
const beforeEventData = { key, members: Array.isArray(members) ? members : [members], cancel: false };
|
|
2708
|
+
this.emit('zrem_before', beforeEventData);
|
|
2709
|
+
|
|
2710
|
+
if (beforeEventData.cancel) {
|
|
2711
|
+
$.log.debug(`[Redis] zrem操作被事件处理器取消 [${key}]`);
|
|
2712
|
+
return 0;
|
|
2713
|
+
}
|
|
2714
|
+
|
|
2715
|
+
const { key: finalKey, members: finalMembers } = beforeEventData;
|
|
2716
|
+
|
|
2717
|
+
const connection = await this._getConnection();
|
|
2718
|
+
try {
|
|
2719
|
+
const args = [this.applyPrefix(finalKey), ...finalMembers];
|
|
2720
|
+
const result = await connection.execute('zrem', ...args);
|
|
2721
|
+
|
|
2722
|
+
// 触发后置事件
|
|
2723
|
+
this.emit('zrem_after', { key: finalKey, members: finalMembers, result });
|
|
2724
|
+
return result;
|
|
2725
|
+
} finally {
|
|
2726
|
+
this._recycleConnection(connection);
|
|
2727
|
+
}
|
|
2728
|
+
} catch (err) {
|
|
2729
|
+
$.log.error(`[Redis] 移除有序集合成员失败 [${key}]:`, err);
|
|
2730
|
+
this.emit('zrem_error', { key, members, error: err });
|
|
2731
|
+
return 0;
|
|
2732
|
+
}
|
|
2820
2733
|
};
|
|
2821
2734
|
|
|
2822
2735
|
/**
|
|
@@ -2825,19 +2738,20 @@ Redis.prototype.zrem = async function(key, members) {
|
|
|
2825
2738
|
* @param {String} member 成员
|
|
2826
2739
|
* @return {Promise<Number|null>} 分数
|
|
2827
2740
|
*/
|
|
2828
|
-
Redis.prototype.zscore = async function(key, member) {
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2741
|
+
Redis.prototype.zscore = async function (key, member) {
|
|
2742
|
+
try {
|
|
2743
|
+
const connection = await this._getConnection();
|
|
2744
|
+
try {
|
|
2745
|
+
const prefixedKey = this.applyPrefix(key);
|
|
2746
|
+
const result = await connection.zScore(prefixedKey, member);
|
|
2747
|
+
return result ? parseFloat(result) : null;
|
|
2748
|
+
} finally {
|
|
2749
|
+
this._recycleConnection(connection);
|
|
2750
|
+
}
|
|
2751
|
+
} catch (err) {
|
|
2752
|
+
$.log.error(`[Redis] 获取有序集合成员分数失败 [${key}:${member}]:`, err);
|
|
2753
|
+
return null;
|
|
2754
|
+
}
|
|
2841
2755
|
};
|
|
2842
2756
|
|
|
2843
2757
|
/**
|
|
@@ -2846,19 +2760,20 @@ Redis.prototype.zscore = async function(key, member) {
|
|
|
2846
2760
|
* @param {String} member 成员
|
|
2847
2761
|
* @return {Promise<Number|null>} 排名
|
|
2848
2762
|
*/
|
|
2849
|
-
Redis.prototype.zrank = async function(key, member) {
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2763
|
+
Redis.prototype.zrank = async function (key, member) {
|
|
2764
|
+
try {
|
|
2765
|
+
const connection = await this._getConnection();
|
|
2766
|
+
try {
|
|
2767
|
+
const prefixedKey = this.applyPrefix(key);
|
|
2768
|
+
const result = await connection.zRank(prefixedKey, member);
|
|
2769
|
+
return result;
|
|
2770
|
+
} finally {
|
|
2771
|
+
this._recycleConnection(connection);
|
|
2772
|
+
}
|
|
2773
|
+
} catch (err) {
|
|
2774
|
+
$.log.error(`[Redis] 获取有序集合成员排名失败 [${key}:${member}]:`, err);
|
|
2775
|
+
return null;
|
|
2776
|
+
}
|
|
2862
2777
|
};
|
|
2863
2778
|
|
|
2864
2779
|
/**
|
|
@@ -2869,34 +2784,33 @@ Redis.prototype.zrank = async function(key, member) {
|
|
|
2869
2784
|
* @param {Boolean} withScores 是否返回分数
|
|
2870
2785
|
* @return {Promise<Array>} 成员数组
|
|
2871
2786
|
*/
|
|
2872
|
-
Redis.prototype.zrange = async function(key, start, stop, withScores = false) {
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
}
|
|
2787
|
+
Redis.prototype.zrange = async function (key, start, stop, withScores = false) {
|
|
2788
|
+
try {
|
|
2789
|
+
const connection = await this._getConnection();
|
|
2790
|
+
try {
|
|
2791
|
+
const prefixedKey = this.applyPrefix(key);
|
|
2792
|
+
const result = await connection.zRange(prefixedKey, start, stop, { WITHSCORES: withScores });
|
|
2793
|
+
|
|
2794
|
+
// 如果需要返回分数,将结果转换为对象数组
|
|
2795
|
+
if (withScores && result && result.length) {
|
|
2796
|
+
const formattedResult = [];
|
|
2797
|
+
for (let i = 0; i < result.length; i += 2) {
|
|
2798
|
+
formattedResult.push({
|
|
2799
|
+
member: result[i],
|
|
2800
|
+
score: parseFloat(result[i + 1])
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
return formattedResult;
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
return result || [];
|
|
2807
|
+
} finally {
|
|
2808
|
+
this._recycleConnection(connection);
|
|
2809
|
+
}
|
|
2810
|
+
} catch (err) {
|
|
2811
|
+
$.log.error(`[Redis] 获取有序集合范围成员失败 [${key}]:`, err);
|
|
2812
|
+
return [];
|
|
2813
|
+
}
|
|
2900
2814
|
};
|
|
2901
2815
|
|
|
2902
2816
|
/**
|
|
@@ -2904,19 +2818,19 @@ Redis.prototype.zrange = async function(key, start, stop, withScores = false) {
|
|
|
2904
2818
|
* @param {String} key 键
|
|
2905
2819
|
* @return {Promise<Number>} 成员数量
|
|
2906
2820
|
*/
|
|
2907
|
-
Redis.prototype.zcard = async function(key) {
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2821
|
+
Redis.prototype.zcard = async function (key) {
|
|
2822
|
+
try {
|
|
2823
|
+
const connection = await this._getConnection();
|
|
2824
|
+
try {
|
|
2825
|
+
const result = await connection.execute('zcard', this.applyPrefix(key));
|
|
2826
|
+
return result || 0;
|
|
2827
|
+
} finally {
|
|
2828
|
+
this._recycleConnection(connection);
|
|
2829
|
+
}
|
|
2830
|
+
} catch (err) {
|
|
2831
|
+
$.log.error(`[Redis] 获取有序集合成员数量失败 [${key}]:`, err);
|
|
2832
|
+
return 0;
|
|
2833
|
+
}
|
|
2920
2834
|
};
|
|
2921
2835
|
|
|
2922
2836
|
/**
|
|
@@ -2926,366 +2840,108 @@ Redis.prototype.zcard = async function(key) {
|
|
|
2926
2840
|
* @param {String} member 成员
|
|
2927
2841
|
* @return {Promise<Number>} 增加后的分数
|
|
2928
2842
|
*/
|
|
2929
|
-
Redis.prototype.zincrby = async function(key, increment, member) {
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
};
|
|
2958
|
-
|
|
2959
|
-
//
|
|
2960
|
-
Redis.prototype._createConnection = function() {
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
key = args[0];
|
|
3035
|
-
const targetHashVals = hashStore.get(key);
|
|
3036
|
-
if (!targetHashVals) return [];
|
|
3037
|
-
return Array.from(targetHashVals.values());
|
|
3038
|
-
|
|
3039
|
-
// 新增命令支持
|
|
3040
|
-
case 'expire':
|
|
3041
|
-
// 模拟过期时间(实际实现需要定时器)
|
|
3042
|
-
return 1;
|
|
3043
|
-
case 'incr':
|
|
3044
|
-
key = args[0];
|
|
3045
|
-
const currentVal = memoryStore.get(key) || 0;
|
|
3046
|
-
const newVal = parseInt(currentVal) + 1;
|
|
3047
|
-
memoryStore.set(key, newVal.toString());
|
|
3048
|
-
return newVal;
|
|
3049
|
-
case 'decr':
|
|
3050
|
-
key = args[0];
|
|
3051
|
-
const currVal = memoryStore.get(key) || 0;
|
|
3052
|
-
const decrVal = parseInt(currVal) - 1;
|
|
3053
|
-
memoryStore.set(key, decrVal.toString());
|
|
3054
|
-
return decrVal;
|
|
3055
|
-
case 'incrby':
|
|
3056
|
-
key = args[0];
|
|
3057
|
-
const increment = parseInt(args[1]) || 0;
|
|
3058
|
-
const incrCurrent = memoryStore.get(key) || 0;
|
|
3059
|
-
const incrResult = parseInt(incrCurrent) + increment;
|
|
3060
|
-
memoryStore.set(key, incrResult.toString());
|
|
3061
|
-
return incrResult;
|
|
3062
|
-
case 'decrby':
|
|
3063
|
-
key = args[0];
|
|
3064
|
-
const decrement = parseInt(args[1]) || 0;
|
|
3065
|
-
const decrCurrent = memoryStore.get(key) || 0;
|
|
3066
|
-
const decrResult = parseInt(decrCurrent) - decrement;
|
|
3067
|
-
memoryStore.set(key, decrResult.toString());
|
|
3068
|
-
return decrResult;
|
|
3069
|
-
|
|
3070
|
-
// 集合操作命令
|
|
3071
|
-
case 'sadd':
|
|
3072
|
-
key = args[0];
|
|
3073
|
-
if (!setStore.has(key)) {
|
|
3074
|
-
setStore.set(key, new Set());
|
|
3075
|
-
}
|
|
3076
|
-
const set = setStore.get(key);
|
|
3077
|
-
let addedCount = 0;
|
|
3078
|
-
for (let i = 1; i < args.length; i++) {
|
|
3079
|
-
if (!set.has(args[i])) {
|
|
3080
|
-
set.add(args[i]);
|
|
3081
|
-
addedCount++;
|
|
3082
|
-
}
|
|
3083
|
-
}
|
|
3084
|
-
return addedCount;
|
|
3085
|
-
case 'srem':
|
|
3086
|
-
key = args[0];
|
|
3087
|
-
const targetSet = setStore.get(key);
|
|
3088
|
-
if (!targetSet) return 0;
|
|
3089
|
-
let removedCount = 0;
|
|
3090
|
-
for (let i = 1; i < args.length; i++) {
|
|
3091
|
-
if (targetSet.has(args[i])) {
|
|
3092
|
-
targetSet.delete(args[i]);
|
|
3093
|
-
removedCount++;
|
|
3094
|
-
}
|
|
3095
|
-
}
|
|
3096
|
-
return removedCount;
|
|
3097
|
-
case 'sismember':
|
|
3098
|
-
key = args[0];
|
|
3099
|
-
member = args[1];
|
|
3100
|
-
const checkSet = setStore.get(key);
|
|
3101
|
-
return checkSet && checkSet.has(member) ? 1 : 0;
|
|
3102
|
-
case 'smembers':
|
|
3103
|
-
key = args[0];
|
|
3104
|
-
const membersSet = setStore.get(key);
|
|
3105
|
-
return membersSet ? Array.from(membersSet) : [];
|
|
3106
|
-
case 'scard':
|
|
3107
|
-
key = args[0];
|
|
3108
|
-
const countSet = setStore.get(key);
|
|
3109
|
-
return countSet ? countSet.size : 0;
|
|
3110
|
-
case 'sinter':
|
|
3111
|
-
// 简单实现集合交集
|
|
3112
|
-
const sets = args.map(k => setStore.get(k)).filter(s => s);
|
|
3113
|
-
if (sets.length === 0) return [];
|
|
3114
|
-
let intersection = new Set(sets[0]);
|
|
3115
|
-
for (let i = 1; i < sets.length; i++) {
|
|
3116
|
-
intersection = new Set([...intersection].filter(x => sets[i].has(x)));
|
|
3117
|
-
}
|
|
3118
|
-
return Array.from(intersection);
|
|
3119
|
-
case 'sunion':
|
|
3120
|
-
// 简单实现集合并集
|
|
3121
|
-
const unionSets = args.map(k => setStore.get(k)).filter(s => s);
|
|
3122
|
-
const union = new Set();
|
|
3123
|
-
unionSets.forEach(set => {
|
|
3124
|
-
set.forEach(member => union.add(member));
|
|
3125
|
-
});
|
|
3126
|
-
return Array.from(union);
|
|
3127
|
-
case 'sdiff':
|
|
3128
|
-
// 简单实现集合差集
|
|
3129
|
-
if (args.length === 0) return [];
|
|
3130
|
-
const firstSet = setStore.get(args[0]);
|
|
3131
|
-
if (!firstSet) return [];
|
|
3132
|
-
const diff = new Set(firstSet);
|
|
3133
|
-
for (let i = 1; i < args.length; i++) {
|
|
3134
|
-
const otherSet = setStore.get(args[i]);
|
|
3135
|
-
if (otherSet) {
|
|
3136
|
-
otherSet.forEach(member => diff.delete(member));
|
|
3137
|
-
}
|
|
3138
|
-
}
|
|
3139
|
-
return Array.from(diff);
|
|
3140
|
-
|
|
3141
|
-
// 有序集合操作命令
|
|
3142
|
-
case 'zadd':
|
|
3143
|
-
key = args[0];
|
|
3144
|
-
score = parseFloat(args[1]);
|
|
3145
|
-
member = args[2];
|
|
3146
|
-
|
|
3147
|
-
if (!sortedSetStore.has(key)) {
|
|
3148
|
-
sortedSetStore.set(key, new Map());
|
|
3149
|
-
}
|
|
3150
|
-
const sortedSet = sortedSetStore.get(key);
|
|
3151
|
-
sortedSet.set(member, score);
|
|
3152
|
-
return 1;
|
|
3153
|
-
case 'zrem':
|
|
3154
|
-
key = args[0];
|
|
3155
|
-
const targetSortedSet = sortedSetStore.get(key);
|
|
3156
|
-
if (!targetSortedSet) return 0;
|
|
3157
|
-
let removedSortedCount = 0;
|
|
3158
|
-
for (let i = 1; i < args.length; i++) {
|
|
3159
|
-
if (targetSortedSet.has(args[i])) {
|
|
3160
|
-
targetSortedSet.delete(args[i]);
|
|
3161
|
-
removedSortedCount++;
|
|
3162
|
-
}
|
|
3163
|
-
}
|
|
3164
|
-
return removedSortedCount;
|
|
3165
|
-
case 'zscore':
|
|
3166
|
-
key = args[0];
|
|
3167
|
-
member = args[1];
|
|
3168
|
-
const scoreSet = sortedSetStore.get(key);
|
|
3169
|
-
return scoreSet && scoreSet.has(member) ? scoreSet.get(member).toString() : null;
|
|
3170
|
-
case 'zrank':
|
|
3171
|
-
key = args[0];
|
|
3172
|
-
member = args[1];
|
|
3173
|
-
const rankSet = sortedSetStore.get(key);
|
|
3174
|
-
if (!rankSet || !rankSet.has(member)) return null;
|
|
3175
|
-
|
|
3176
|
-
// 排序获取排名
|
|
3177
|
-
const sortedEntries = Array.from(rankSet.entries()).sort((a, b) => a[1] - b[1]);
|
|
3178
|
-
for (let i = 0; i < sortedEntries.length; i++) {
|
|
3179
|
-
if (sortedEntries[i][0] === member) {
|
|
3180
|
-
return i;
|
|
3181
|
-
}
|
|
3182
|
-
}
|
|
3183
|
-
return null;
|
|
3184
|
-
case 'zrange':
|
|
3185
|
-
key = args[0];
|
|
3186
|
-
const start = parseInt(args[1]);
|
|
3187
|
-
const stop = parseInt(args[2]);
|
|
3188
|
-
const withScores = args[3] === 'WITHSCORES';
|
|
3189
|
-
|
|
3190
|
-
const rangeSet = sortedSetStore.get(key);
|
|
3191
|
-
if (!rangeSet) return withScores ? [] : [];
|
|
3192
|
-
|
|
3193
|
-
// 排序并获取范围
|
|
3194
|
-
const sorted = Array.from(rangeSet.entries()).sort((a, b) => a[1] - b[1]);
|
|
3195
|
-
const slice = sorted.slice(start, stop + 1);
|
|
3196
|
-
|
|
3197
|
-
if (withScores) {
|
|
3198
|
-
const result = [];
|
|
3199
|
-
slice.forEach(([member, score]) => {
|
|
3200
|
-
result.push(member, score.toString());
|
|
3201
|
-
});
|
|
3202
|
-
return result;
|
|
3203
|
-
} else {
|
|
3204
|
-
return slice.map(([member]) => member);
|
|
3205
|
-
}
|
|
3206
|
-
case 'zcard':
|
|
3207
|
-
key = args[0];
|
|
3208
|
-
const cardSet = sortedSetStore.get(key);
|
|
3209
|
-
return cardSet ? cardSet.size : 0;
|
|
3210
|
-
case 'zincrby':
|
|
3211
|
-
key = args[0];
|
|
3212
|
-
const zincrbyIncrement = parseFloat(args[1]);
|
|
3213
|
-
const zincrbyMember = args[2];
|
|
3214
|
-
|
|
3215
|
-
if (!sortedSetStore.has(key)) {
|
|
3216
|
-
sortedSetStore.set(key, new Map());
|
|
3217
|
-
}
|
|
3218
|
-
const incrSortedSet = sortedSetStore.get(key);
|
|
3219
|
-
const currentScore = incrSortedSet.get(zincrbyMember) || 0;
|
|
3220
|
-
const newScore = currentScore + zincrbyIncrement;
|
|
3221
|
-
incrSortedSet.set(zincrbyMember, newScore);
|
|
3222
|
-
return newScore.toString();
|
|
3223
|
-
|
|
3224
|
-
default:
|
|
3225
|
-
return 'OK';
|
|
3226
|
-
}
|
|
3227
|
-
},
|
|
3228
|
-
// 支持Redis客户端的直接方法调用
|
|
3229
|
-
set: async (key, value, options) => {
|
|
3230
|
-
memoryStore.set(key, value);
|
|
3231
|
-
return 'OK';
|
|
3232
|
-
},
|
|
3233
|
-
get: async (key) => {
|
|
3234
|
-
return memoryStore.get(key) || null;
|
|
3235
|
-
},
|
|
3236
|
-
del: async (key) => {
|
|
3237
|
-
memoryStore.delete(key);
|
|
3238
|
-
hashStore.delete(key);
|
|
3239
|
-
setStore.delete(key);
|
|
3240
|
-
sortedSetStore.delete(key);
|
|
3241
|
-
return 1;
|
|
3242
|
-
},
|
|
3243
|
-
exists: async (key) => {
|
|
3244
|
-
return memoryStore.has(key) || hashStore.has(key) || setStore.has(key) || sortedSetStore.has(key) ? 1 : 0;
|
|
3245
|
-
},
|
|
3246
|
-
hSet: async (key, field, value) => {
|
|
3247
|
-
if (!hashStore.has(key)) {
|
|
3248
|
-
hashStore.set(key, new Map());
|
|
3249
|
-
}
|
|
3250
|
-
const hash = hashStore.get(key);
|
|
3251
|
-
hash.set(field, value);
|
|
3252
|
-
return 1;
|
|
3253
|
-
},
|
|
3254
|
-
hGet: async (key, field) => {
|
|
3255
|
-
const targetHash = hashStore.get(key);
|
|
3256
|
-
if (targetHash && targetHash.has(field)) {
|
|
3257
|
-
return targetHash.get(field);
|
|
3258
|
-
}
|
|
3259
|
-
return null;
|
|
3260
|
-
},
|
|
3261
|
-
multi: function() {
|
|
3262
|
-
// 返回简单的pipeline实现
|
|
3263
|
-
return {
|
|
3264
|
-
commands: [],
|
|
3265
|
-
set: function(key, value, options) {
|
|
3266
|
-
this.commands.push(['set', key, value, options]);
|
|
3267
|
-
return this;
|
|
3268
|
-
},
|
|
3269
|
-
get: function(key) {
|
|
3270
|
-
this.commands.push(['get', key]);
|
|
3271
|
-
return this;
|
|
3272
|
-
},
|
|
3273
|
-
exec: async function() {
|
|
3274
|
-
// 模拟执行pipeline中的命令
|
|
3275
|
-
return this.commands.map(cmd => [null, 'OK']);
|
|
3276
|
-
}
|
|
3277
|
-
};
|
|
3278
|
-
},
|
|
3279
|
-
close: () => {
|
|
3280
|
-
$.log.debug('[Redis] 关闭连接');
|
|
3281
|
-
}
|
|
3282
|
-
};
|
|
3283
|
-
|
|
3284
|
-
$.log.debug('[Redis] 新连接已创建:', connection.id);
|
|
3285
|
-
resolve(connection);
|
|
3286
|
-
} catch (error) {
|
|
3287
|
-
$.log.error('[Redis] 创建连接失败:', error);
|
|
3288
|
-
reject(error);
|
|
3289
|
-
}
|
|
3290
|
-
});
|
|
3291
|
-
};
|
|
2843
|
+
Redis.prototype.zincrby = async function (key, increment, member) {
|
|
2844
|
+
try {
|
|
2845
|
+
// 触发前置事件
|
|
2846
|
+
const beforeEventData = { key, increment, member, cancel: false };
|
|
2847
|
+
this.emit('zincrby_before', beforeEventData);
|
|
2848
|
+
|
|
2849
|
+
if (beforeEventData.cancel) {
|
|
2850
|
+
$.log.debug(`[Redis] zincrby操作被事件处理器取消 [${key}]`);
|
|
2851
|
+
return null;
|
|
2852
|
+
}
|
|
2853
|
+
|
|
2854
|
+
const { key: finalKey, increment: finalIncrement, member: finalMember } = beforeEventData;
|
|
2855
|
+
|
|
2856
|
+
const connection = await this._getConnection();
|
|
2857
|
+
try {
|
|
2858
|
+
const result = await connection.execute('zincrby', this.applyPrefix(finalKey), finalIncrement, finalMember);
|
|
2859
|
+
|
|
2860
|
+
// 触发后置事件
|
|
2861
|
+
this.emit('zincrby_after', { key: finalKey, increment: finalIncrement, member: finalMember, result: parseFloat(result) });
|
|
2862
|
+
return parseFloat(result);
|
|
2863
|
+
} finally {
|
|
2864
|
+
this._recycleConnection(connection);
|
|
2865
|
+
}
|
|
2866
|
+
} catch (err) {
|
|
2867
|
+
$.log.error(`[Redis] 增加有序集合成员分数失败 [${key}]:`, err);
|
|
2868
|
+
this.emit('zincrby_error', { key, increment, member, error: err });
|
|
2869
|
+
return null;
|
|
2870
|
+
}
|
|
2871
|
+
};
|
|
2872
|
+
|
|
2873
|
+
// 创建真实Redis连接的方法
|
|
2874
|
+
Redis.prototype._createConnection = function () {
|
|
2875
|
+
return new Promise((resolve, reject) => {
|
|
2876
|
+
try {
|
|
2877
|
+
const cg = this.config;
|
|
2878
|
+
|
|
2879
|
+
// 创建真实的Redis客户端连接
|
|
2880
|
+
const connection = createClient({
|
|
2881
|
+
socket: {
|
|
2882
|
+
host: cg.host,
|
|
2883
|
+
port: cg.port,
|
|
2884
|
+
timeout: cg.connect_timeout
|
|
2885
|
+
},
|
|
2886
|
+
password: cg.password,
|
|
2887
|
+
database: cg.database
|
|
2888
|
+
});
|
|
2889
|
+
|
|
2890
|
+
// 添加标识符
|
|
2891
|
+
connection.id = Date.now() + Math.random();
|
|
2892
|
+
|
|
2893
|
+
// 监听错误事件
|
|
2894
|
+
connection.on('error', (err) => {
|
|
2895
|
+
$.log.error(`[Redis] 连接 ${connection.id} 错误:`, err);
|
|
2896
|
+
});
|
|
2897
|
+
|
|
2898
|
+
// 连接Redis
|
|
2899
|
+
connection.connect().then(() => {
|
|
2900
|
+
$.log.debug('[Redis] 新连接已创建并连接:', connection.id);
|
|
2901
|
+
resolve(connection);
|
|
2902
|
+
}).catch(err => {
|
|
2903
|
+
$.log.error('[Redis] 创建连接失败:', err);
|
|
2904
|
+
reject(err);
|
|
2905
|
+
});
|
|
2906
|
+
} catch (error) {
|
|
2907
|
+
$.log.error('[Redis] 创建连接时发生异常:', error);
|
|
2908
|
+
reject(error);
|
|
2909
|
+
}
|
|
2910
|
+
});
|
|
2911
|
+
};
|
|
2912
|
+
|
|
2913
|
+
// 修改导出方式以支持多种导入格式
|
|
2914
|
+
exports.Redis = Redis;
|
|
2915
|
+
|
|
2916
|
+
/**
|
|
2917
|
+
* 确保连接池对象存在
|
|
2918
|
+
*/
|
|
2919
|
+
if (!$.pool) {
|
|
2920
|
+
$.pool = {};
|
|
2921
|
+
}
|
|
2922
|
+
if (!$.pool.redis) {
|
|
2923
|
+
$.pool.redis = {};
|
|
2924
|
+
}
|
|
2925
|
+
|
|
2926
|
+
/**
|
|
2927
|
+
* @description Redis管理器,用于创建缓存
|
|
2928
|
+
* @param {String} scope 作用域
|
|
2929
|
+
* @param {String} dir 当前路径
|
|
2930
|
+
* @return {Object} 返回一个Redis类实例
|
|
2931
|
+
*/
|
|
2932
|
+
function redis_admin(scope, dir) {
|
|
2933
|
+
if (!scope) {
|
|
2934
|
+
scope = 'sys';
|
|
2935
|
+
}
|
|
2936
|
+
var obj = $.pool.redis[scope];
|
|
2937
|
+
if (!obj) {
|
|
2938
|
+
$.pool.redis[scope] = new Redis(scope, dir);
|
|
2939
|
+
obj = $.pool.redis[scope];
|
|
2940
|
+
}
|
|
2941
|
+
return obj;
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2944
|
+
/**
|
|
2945
|
+
* @module 导出Redis管理器
|
|
2946
|
+
*/
|
|
2947
|
+
exports.redis_admin = redis_admin;
|