mm_redis 1.9.8 → 1.9.9
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/LICENSE +15 -0
- package/README.md +64 -25
- package/index.js +1832 -521
- package/package.json +2 -2
- package/test.js +20 -20
- package/test_hmset.js +91 -0
- package/compatibility_table.md +0 -103
- package/verify_compatibility.js +0 -175
package/index.js
CHANGED
|
@@ -3,8 +3,9 @@
|
|
|
3
3
|
* @author <a href="http://qww.elins.cn">邱文武</a>
|
|
4
4
|
* @version 1.5.0
|
|
5
5
|
*/
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const {
|
|
7
|
+
BaseService
|
|
8
|
+
} = require('mm_base_service');
|
|
8
9
|
const {
|
|
9
10
|
createClient
|
|
10
11
|
} = require('redis');
|
|
@@ -13,17 +14,14 @@ const {
|
|
|
13
14
|
|
|
14
15
|
/* 创建Redis帮助类函数 */
|
|
15
16
|
/// 构造函数
|
|
16
|
-
class Redis extends
|
|
17
|
+
class Redis extends BaseService {
|
|
17
18
|
/**
|
|
18
19
|
* @description 创建Redis帮助类函数 (构造函数)
|
|
19
|
-
* @param {String} scope 作用域
|
|
20
20
|
* @param {Object} config 配置参数
|
|
21
21
|
* @constructor
|
|
22
22
|
*/
|
|
23
|
-
constructor(
|
|
23
|
+
constructor(config) {
|
|
24
24
|
super();
|
|
25
|
-
// 作用域
|
|
26
|
-
this.scope = scope;
|
|
27
25
|
// 配置参数
|
|
28
26
|
this.config = {
|
|
29
27
|
// 服务器地址
|
|
@@ -31,7 +29,7 @@ class Redis extends eventEmitter {
|
|
|
31
29
|
// 端口号
|
|
32
30
|
"port": 6379,
|
|
33
31
|
// 密码
|
|
34
|
-
"password": "",
|
|
32
|
+
"password": "asd159357",
|
|
35
33
|
// 数据库
|
|
36
34
|
"database": 0,
|
|
37
35
|
// 前缀
|
|
@@ -45,9 +43,9 @@ class Redis extends eventEmitter {
|
|
|
45
43
|
};
|
|
46
44
|
this.setConfig(config);
|
|
47
45
|
// 连接池配置
|
|
48
|
-
this.
|
|
46
|
+
this.connection_pool = {
|
|
49
47
|
available: [], // 可用连接数组
|
|
50
|
-
|
|
48
|
+
in_use: new Set(), // 使用中的连接集合
|
|
51
49
|
config: {
|
|
52
50
|
max_clients: 10 // 最大连接数
|
|
53
51
|
}
|
|
@@ -59,7 +57,7 @@ class Redis extends eventEmitter {
|
|
|
59
57
|
// 连接状态
|
|
60
58
|
this.connected = false;
|
|
61
59
|
// 重试次数计数器
|
|
62
|
-
this.
|
|
60
|
+
this.retry_count = 0;
|
|
63
61
|
// 订阅回调函数
|
|
64
62
|
this.func_list = {};
|
|
65
63
|
}
|
|
@@ -70,7 +68,7 @@ class Redis extends eventEmitter {
|
|
|
70
68
|
* @param {String} key 键
|
|
71
69
|
* @return {String} 处理后的键
|
|
72
70
|
*/
|
|
73
|
-
Redis.prototype.applyPrefix = function
|
|
71
|
+
Redis.prototype.applyPrefix = function(key) {
|
|
74
72
|
return this.config.prefix ? this.config.prefix + key : key;
|
|
75
73
|
};
|
|
76
74
|
|
|
@@ -79,7 +77,7 @@ Redis.prototype.applyPrefix = function (key) {
|
|
|
79
77
|
* @param {String} key 带前缀的键
|
|
80
78
|
* @return {String} 处理后的键
|
|
81
79
|
*/
|
|
82
|
-
Redis.prototype.removePrefix = function
|
|
80
|
+
Redis.prototype.removePrefix = function(key) {
|
|
83
81
|
if (this.config.prefix && key.startsWith(this.config.prefix)) {
|
|
84
82
|
return key.slice(this.config.prefix.length);
|
|
85
83
|
}
|
|
@@ -92,7 +90,7 @@ Redis.prototype.removePrefix = function (key) {
|
|
|
92
90
|
* @param {Function} func 操作回调函数,可判断成功与否
|
|
93
91
|
* @return {Promise<Boolean>} 订阅结果
|
|
94
92
|
*/
|
|
95
|
-
Redis.prototype.subscribe = async function
|
|
93
|
+
Redis.prototype.subscribe = async function(channel, func) {
|
|
96
94
|
try {
|
|
97
95
|
await this.conn.subscribe(this.applyPrefix(channel));
|
|
98
96
|
this.func_list[channel] = func;
|
|
@@ -108,7 +106,7 @@ Redis.prototype.subscribe = async function (channel, func) {
|
|
|
108
106
|
* @param {String} channel 订阅的频道
|
|
109
107
|
* @return {Promise<Boolean>} 取消订阅结果
|
|
110
108
|
*/
|
|
111
|
-
Redis.prototype.unsubscribe = async function
|
|
109
|
+
Redis.prototype.unsubscribe = async function(channel) {
|
|
112
110
|
try {
|
|
113
111
|
await this.conn.unsubscribe(this.applyPrefix(channel));
|
|
114
112
|
delete this.func_list[channel];
|
|
@@ -125,12 +123,13 @@ Redis.prototype.unsubscribe = async function (channel) {
|
|
|
125
123
|
* @param {String} message 订阅的消息
|
|
126
124
|
* @return {Promise<Number>} 接收消息的客户端数量
|
|
127
125
|
*/
|
|
128
|
-
Redis.prototype.publish = async function
|
|
126
|
+
Redis.prototype.publish = async function(channel, message) {
|
|
129
127
|
try {
|
|
130
128
|
return await this.conn.publish(this.applyPrefix(channel), message);
|
|
131
129
|
} catch (err) {
|
|
132
130
|
$.log.error(`[Redis] 发布消息到频道 ${channel} 失败:`, err);
|
|
133
|
-
|
|
131
|
+
$.log.error('[Redis] 操作失败:', err);
|
|
132
|
+
return false;
|
|
134
133
|
}
|
|
135
134
|
};
|
|
136
135
|
|
|
@@ -139,7 +138,7 @@ Redis.prototype.publish = async function (channel, message) {
|
|
|
139
138
|
* @param {String} channel
|
|
140
139
|
* @param {String} message
|
|
141
140
|
*/
|
|
142
|
-
Redis.prototype.main = async function
|
|
141
|
+
Redis.prototype.main = async function(channel, message) {
|
|
143
142
|
// 默认实现,可由子类重写
|
|
144
143
|
$.log.debug(`[Redis] 收到未处理的消息 [${channel}]:`, message);
|
|
145
144
|
};
|
|
@@ -149,7 +148,7 @@ Redis.prototype.main = async function (channel, message) {
|
|
|
149
148
|
* @param {String} channel 频道
|
|
150
149
|
* @param {String} message 消息
|
|
151
150
|
*/
|
|
152
|
-
Redis.prototype.message = function
|
|
151
|
+
Redis.prototype.message = function(channel, message) {
|
|
153
152
|
// 移除前缀
|
|
154
153
|
channel = this.removePrefix(channel);
|
|
155
154
|
var func = this.func_list[channel];
|
|
@@ -166,18 +165,17 @@ Redis.prototype.message = function (channel, message) {
|
|
|
166
165
|
|
|
167
166
|
/**
|
|
168
167
|
* @description 设置配置
|
|
169
|
-
* @param {Object}
|
|
168
|
+
* @param {Object} config 配置对象或配置路径
|
|
170
169
|
*/
|
|
171
170
|
// 修复setConfig方法,移除其中的_initPool定义
|
|
172
|
-
Redis.prototype.setConfig = function
|
|
171
|
+
Redis.prototype.setConfig = function(config) {
|
|
173
172
|
let obj = {};
|
|
174
|
-
if (typeof
|
|
175
|
-
obj =
|
|
176
|
-
} else if (
|
|
177
|
-
|
|
178
|
-
Object.assign(this.config,
|
|
179
|
-
}
|
|
180
|
-
else {
|
|
173
|
+
if (typeof config === 'string') {
|
|
174
|
+
obj = config.loadJson(__dirname);
|
|
175
|
+
} else if (config) {
|
|
176
|
+
// 合并配置参数
|
|
177
|
+
Object.assign(this.config, config);
|
|
178
|
+
} else {
|
|
181
179
|
return;
|
|
182
180
|
}
|
|
183
181
|
// 使用Object.assign替代$.push来合并配置
|
|
@@ -199,11 +197,11 @@ Redis.prototype.setConfig = function (cg) {
|
|
|
199
197
|
};
|
|
200
198
|
|
|
201
199
|
// 添加连接池初始化方法
|
|
202
|
-
Redis.prototype._initPool = function
|
|
200
|
+
Redis.prototype._initPool = function() {
|
|
203
201
|
// 初始化连接池相关属性
|
|
204
|
-
this.
|
|
202
|
+
this.connection_pool = {
|
|
205
203
|
available: [],
|
|
206
|
-
|
|
204
|
+
in_use: new Set(),
|
|
207
205
|
config: this.config.pool || {
|
|
208
206
|
max_clients: 10,
|
|
209
207
|
min_idle: 2,
|
|
@@ -220,14 +218,14 @@ Redis.prototype._initPool = function () {
|
|
|
220
218
|
* @description 连接Redis数据库
|
|
221
219
|
* @return {Promise<Boolean>} 连接结果
|
|
222
220
|
*/
|
|
223
|
-
Redis.prototype.open = async function
|
|
221
|
+
Redis.prototype.open = async function() {
|
|
224
222
|
if (this.conn && this.connected) {
|
|
225
223
|
return true;
|
|
226
224
|
}
|
|
227
225
|
|
|
228
226
|
try {
|
|
229
227
|
const cg = this.config;
|
|
230
|
-
this.
|
|
228
|
+
this.retry_count = 0;
|
|
231
229
|
|
|
232
230
|
// 创建客户端
|
|
233
231
|
this.conn = createClient({
|
|
@@ -252,7 +250,7 @@ Redis.prototype.open = async function () {
|
|
|
252
250
|
this.conn.on('connect', () => {
|
|
253
251
|
$.log.debug('[Redis] Redis已连接');
|
|
254
252
|
this.connected = true;
|
|
255
|
-
this.
|
|
253
|
+
this.retry_count = 0;
|
|
256
254
|
});
|
|
257
255
|
|
|
258
256
|
// 监听断开连接事件
|
|
@@ -292,14 +290,14 @@ Redis.prototype.open = async function () {
|
|
|
292
290
|
* 内部重连方法
|
|
293
291
|
* @private
|
|
294
292
|
*/
|
|
295
|
-
Redis.prototype._reconnect = function
|
|
296
|
-
if (this.
|
|
293
|
+
Redis.prototype._reconnect = function() {
|
|
294
|
+
if (this.retry_count >= this.config.retry_count) {
|
|
297
295
|
$.log.error(`[Redis] 达到最大重连次数 ${this.config.retry_count},停止重连`);
|
|
298
296
|
return;
|
|
299
297
|
}
|
|
300
298
|
|
|
301
|
-
this.
|
|
302
|
-
$.log.debug(`[Redis] 尝试第 ${this.
|
|
299
|
+
this.retry_count++;
|
|
300
|
+
$.log.debug(`[Redis] 尝试第 ${this.retry_count} 次重连...`);
|
|
303
301
|
|
|
304
302
|
setTimeout(async () => {
|
|
305
303
|
try {
|
|
@@ -315,25 +313,25 @@ Redis.prototype._reconnect = function () {
|
|
|
315
313
|
* @return {Promise<Boolean>} 关闭结果
|
|
316
314
|
*/
|
|
317
315
|
// 修复close方法,正确处理连接池
|
|
318
|
-
Redis.prototype.close = function
|
|
316
|
+
Redis.prototype.close = function() {
|
|
319
317
|
try {
|
|
320
318
|
$.log.debug('[Redis] 关闭所有连接...');
|
|
321
319
|
|
|
322
320
|
// 关闭所有使用中的连接
|
|
323
|
-
if (this.
|
|
324
|
-
for (const connection of this.
|
|
321
|
+
if (this.connection_pool && this.connection_pool.in_use) {
|
|
322
|
+
for (const connection of this.connection_pool.in_use) {
|
|
325
323
|
try {
|
|
326
324
|
connection.close();
|
|
327
325
|
} catch (e) {
|
|
328
326
|
$.log.error('[Redis] 关闭连接失败:', e);
|
|
329
327
|
}
|
|
330
328
|
}
|
|
331
|
-
this.
|
|
329
|
+
this.connection_pool.in_use.clear();
|
|
332
330
|
}
|
|
333
331
|
|
|
334
332
|
// 关闭所有可用连接
|
|
335
|
-
if (this.
|
|
336
|
-
for (const connection of this.
|
|
333
|
+
if (this.connection_pool && this.connection_pool.available) {
|
|
334
|
+
for (const connection of this.connection_pool.available) {
|
|
337
335
|
try {
|
|
338
336
|
// 检查连接对象是否有close方法
|
|
339
337
|
if (typeof connection.close === 'function') {
|
|
@@ -348,7 +346,7 @@ Redis.prototype.close = function () {
|
|
|
348
346
|
$.log.error('[Redis] 关闭连接失败:', e);
|
|
349
347
|
}
|
|
350
348
|
}
|
|
351
|
-
this.
|
|
349
|
+
this.connection_pool.available = [];
|
|
352
350
|
}
|
|
353
351
|
|
|
354
352
|
this.connected = false;
|
|
@@ -361,49 +359,49 @@ Redis.prototype.close = function () {
|
|
|
361
359
|
};
|
|
362
360
|
|
|
363
361
|
// 添加Pipeline支持
|
|
364
|
-
Redis.prototype.pipeline = function
|
|
362
|
+
Redis.prototype.pipeline = function() {
|
|
365
363
|
const redisInstance = this;
|
|
366
364
|
const commands = [];
|
|
367
365
|
|
|
368
366
|
return {
|
|
369
367
|
// 设置值
|
|
370
|
-
set: function
|
|
368
|
+
set: function(key, value, seconds) {
|
|
371
369
|
commands.push(['set', key, value, seconds]);
|
|
372
370
|
return this;
|
|
373
371
|
},
|
|
374
372
|
|
|
375
373
|
// 获取值
|
|
376
|
-
get: function
|
|
374
|
+
get: function(key) {
|
|
377
375
|
commands.push(['get', key]);
|
|
378
376
|
return this;
|
|
379
377
|
},
|
|
380
378
|
|
|
381
379
|
// 删除
|
|
382
|
-
del: function
|
|
380
|
+
del: function(key) {
|
|
383
381
|
commands.push(['del', key]);
|
|
384
382
|
return this;
|
|
385
383
|
},
|
|
386
384
|
|
|
387
385
|
// 判断存在
|
|
388
|
-
has: function
|
|
386
|
+
has: function(key) {
|
|
389
387
|
commands.push(['has', key]);
|
|
390
388
|
return this;
|
|
391
389
|
},
|
|
392
390
|
|
|
393
391
|
// 设置哈希字段
|
|
394
|
-
hset: function
|
|
392
|
+
hset: function(key, field, value) {
|
|
395
393
|
commands.push(['hset', key, field, value]);
|
|
396
394
|
return this;
|
|
397
395
|
},
|
|
398
396
|
|
|
399
397
|
// 过期时间设置
|
|
400
|
-
expire: function
|
|
398
|
+
expire: function(key, seconds) {
|
|
401
399
|
commands.push(['expire', key, seconds]);
|
|
402
400
|
return this;
|
|
403
401
|
},
|
|
404
402
|
|
|
405
403
|
// 执行所有命令
|
|
406
|
-
exec: async function
|
|
404
|
+
exec: async function() {
|
|
407
405
|
try {
|
|
408
406
|
// 使用Redis实例的方法获取连接
|
|
409
407
|
const connection = await redisInstance._getConnection();
|
|
@@ -502,7 +500,7 @@ Redis.prototype.pipeline = function () {
|
|
|
502
500
|
* @description 检查连接状态
|
|
503
501
|
* @return {Boolean} 连接状态
|
|
504
502
|
*/
|
|
505
|
-
Redis.prototype.isConnected = function
|
|
503
|
+
Redis.prototype.isConnected = function() {
|
|
506
504
|
return this.connected && this.conn && this.conn.isReady;
|
|
507
505
|
};
|
|
508
506
|
|
|
@@ -512,12 +510,38 @@ Redis.prototype.isConnected = function () {
|
|
|
512
510
|
* @param {Number} seconds 秒, 为空则查询有效时长
|
|
513
511
|
* @return {Promise<Number|Boolean>} 查询时长或设置结果, 时长为-1表示永不过期
|
|
514
512
|
*/
|
|
515
|
-
|
|
513
|
+
/**
|
|
514
|
+
* 获取或设置键的过期时间
|
|
515
|
+
* @param {String} key 键名
|
|
516
|
+
* @param {Number} [seconds] 过期时间(秒),不传此参数则获取剩余过期时间
|
|
517
|
+
* @return {Promise<Number|Boolean>} 不传seconds时返回剩余过期时间(-1表示无过期设置,-2表示已过期),传seconds时返回是否设置成功
|
|
518
|
+
*/
|
|
519
|
+
Redis.prototype.ttl = async function(key, seconds) {
|
|
516
520
|
try {
|
|
517
521
|
const connection = await this._getConnection();
|
|
518
522
|
try {
|
|
519
523
|
key = this.applyPrefix(key);
|
|
520
|
-
|
|
524
|
+
|
|
525
|
+
// 如果传入了seconds参数,则设置过期时间
|
|
526
|
+
if (seconds !== undefined) {
|
|
527
|
+
if (typeof seconds !== 'number' || isNaN(seconds) || seconds < 0) {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
// 设置过期时间
|
|
532
|
+
if (typeof connection.expire === 'function') {
|
|
533
|
+
await connection.expire(key, seconds);
|
|
534
|
+
return true;
|
|
535
|
+
} else if (typeof connection.execute === 'function') {
|
|
536
|
+
await connection.execute('EXPIRE', [key, seconds]);
|
|
537
|
+
return true;
|
|
538
|
+
} else {
|
|
539
|
+
$.log.error('[Redis] 连接对象不支持expire操作');
|
|
540
|
+
return false;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
// 否则获取剩余过期时间
|
|
521
545
|
if (typeof connection.ttl === 'function') {
|
|
522
546
|
return await connection.ttl(key);
|
|
523
547
|
} else if (typeof connection.execute === 'function') {
|
|
@@ -530,21 +554,37 @@ Redis.prototype.ttl = async function (key) {
|
|
|
530
554
|
this._recycleConnection(connection);
|
|
531
555
|
}
|
|
532
556
|
} catch (err) {
|
|
533
|
-
$.log.error(`[Redis]
|
|
534
|
-
return
|
|
557
|
+
$.log.error(`[Redis] ${seconds !== undefined ? '设置' : '获取'}过期时间失败 [${key}]:`, err);
|
|
558
|
+
return seconds !== undefined ? false : -2;
|
|
535
559
|
}
|
|
536
560
|
};
|
|
537
561
|
|
|
538
562
|
/**
|
|
539
|
-
* @description 增加整数值(负数为减)
|
|
563
|
+
* @description 增加整数值(负数为减)(兼容方法)
|
|
540
564
|
* @param {String} key 键
|
|
541
565
|
* @param {Number} num 数值
|
|
566
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
542
567
|
* @return {Promise<Number>} 计算后的结果
|
|
543
568
|
*/
|
|
544
|
-
Redis.prototype.addInt = async function
|
|
569
|
+
Redis.prototype.addInt = async function(key, num, seconds = 0) {
|
|
545
570
|
try {
|
|
571
|
+
// 参数验证
|
|
572
|
+
if (!key || typeof key !== 'string') {
|
|
573
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
574
|
+
return false;
|
|
575
|
+
}
|
|
576
|
+
if (typeof num !== 'number' || isNaN(num) || !Number.isInteger(num)) {
|
|
577
|
+
$.log.error('[Redis] 参数错误: 数值必须是有效整数');
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
|
|
546
581
|
// 触发前置事件,允许修改或阻止操作
|
|
547
|
-
const beforeEventData = {
|
|
582
|
+
const beforeEventData = {
|
|
583
|
+
key,
|
|
584
|
+
value: num,
|
|
585
|
+
seconds,
|
|
586
|
+
cancel: false
|
|
587
|
+
};
|
|
548
588
|
this.emit('addInt_before', beforeEventData);
|
|
549
589
|
|
|
550
590
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -554,59 +594,83 @@ Redis.prototype.addInt = async function (key, num) {
|
|
|
554
594
|
}
|
|
555
595
|
|
|
556
596
|
// 使用可能被修改的值
|
|
557
|
-
let {
|
|
597
|
+
let {
|
|
598
|
+
key: finalKey,
|
|
599
|
+
value: finalNum,
|
|
600
|
+
seconds: finalSeconds
|
|
601
|
+
} = beforeEventData;
|
|
558
602
|
|
|
559
603
|
const connection = await this._getConnection();
|
|
560
604
|
try {
|
|
561
|
-
|
|
605
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
562
606
|
let result;
|
|
563
607
|
if (finalNum > 0) {
|
|
564
608
|
// 增加整数值
|
|
565
609
|
if (typeof connection.incrBy === 'function') {
|
|
566
|
-
result = await connection.incrBy(
|
|
610
|
+
result = await connection.incrBy(prefixedKey, finalNum);
|
|
567
611
|
} else if (typeof connection.execute === 'function') {
|
|
568
|
-
result = await connection.execute('INCRBY', [
|
|
612
|
+
result = await connection.execute('INCRBY', [prefixedKey, finalNum]);
|
|
569
613
|
} else {
|
|
570
614
|
// 如果出错,回退到先获取再设置的方式
|
|
571
615
|
$.log.warn(`[Redis] 使用原子操作增加整数值失败,使用回退方案`);
|
|
572
|
-
let value = await this.get(
|
|
616
|
+
let value = await this.get(prefixedKey);
|
|
573
617
|
let n = 0;
|
|
574
618
|
if (value) {
|
|
575
619
|
n = Number(value);
|
|
576
620
|
}
|
|
577
621
|
n += finalNum;
|
|
578
|
-
await this.set(
|
|
622
|
+
await this.set(prefixedKey, n, finalSeconds);
|
|
579
623
|
result = n;
|
|
580
624
|
}
|
|
581
625
|
} else {
|
|
582
626
|
// 减少整数值
|
|
583
627
|
if (typeof connection.decrBy === 'function') {
|
|
584
|
-
result = await connection.decrBy(
|
|
628
|
+
result = await connection.decrBy(prefixedKey, -finalNum);
|
|
585
629
|
} else if (typeof connection.execute === 'function') {
|
|
586
|
-
result = await connection.execute('DECRBY', [
|
|
630
|
+
result = await connection.execute('DECRBY', [prefixedKey, -finalNum]);
|
|
587
631
|
} else {
|
|
588
632
|
// 如果出错,回退到先获取再设置的方式
|
|
589
633
|
$.log.warn(`[Redis] 使用原子操作减少整数值失败,使用回退方案`);
|
|
590
|
-
let value = await this.get(
|
|
634
|
+
let value = await this.get(prefixedKey);
|
|
591
635
|
let n = 0;
|
|
592
636
|
if (value) {
|
|
593
637
|
n = Number(value);
|
|
594
638
|
}
|
|
595
639
|
n += finalNum;
|
|
596
|
-
await this.set(
|
|
640
|
+
await this.set(prefixedKey, n, finalSeconds);
|
|
597
641
|
result = n;
|
|
598
642
|
}
|
|
599
643
|
}
|
|
644
|
+
|
|
645
|
+
// 如果设置了过期时间
|
|
646
|
+
if (finalSeconds > 0) {
|
|
647
|
+
if (typeof connection.expire === 'function') {
|
|
648
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
649
|
+
} else if (typeof connection.execute === 'function') {
|
|
650
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
651
|
+
}
|
|
652
|
+
}
|
|
600
653
|
|
|
601
654
|
// 触发后置事件
|
|
602
|
-
this.emit('addInt_after', {
|
|
655
|
+
this.emit('addInt_after', {
|
|
656
|
+
key: finalKey,
|
|
657
|
+
value: finalNum,
|
|
658
|
+
seconds: finalSeconds,
|
|
659
|
+
result,
|
|
660
|
+
success: true
|
|
661
|
+
});
|
|
603
662
|
return result;
|
|
604
663
|
} finally {
|
|
605
664
|
this._recycleConnection(connection);
|
|
606
665
|
}
|
|
607
666
|
} catch (err) {
|
|
608
667
|
// 触发错误事件
|
|
609
|
-
this.emit('addInt_error', {
|
|
668
|
+
this.emit('addInt_error', {
|
|
669
|
+
key,
|
|
670
|
+
value: num,
|
|
671
|
+
seconds,
|
|
672
|
+
error: err
|
|
673
|
+
});
|
|
610
674
|
$.log.error(`[Redis] 增加整数值失败 [${key}]:`, err);
|
|
611
675
|
// 与CacheBase保持一致,错误时返回默认值而不是抛出异常
|
|
612
676
|
return 0;
|
|
@@ -614,15 +678,34 @@ Redis.prototype.addInt = async function (key, num) {
|
|
|
614
678
|
};
|
|
615
679
|
|
|
616
680
|
/**
|
|
617
|
-
* @description 增加浮点数值(负数为减)
|
|
681
|
+
* @description 增加浮点数值(负数为减)(兼容方法)
|
|
618
682
|
* @param {String} key 键
|
|
619
683
|
* @param {Number} num 数值
|
|
684
|
+
* @param {Number} seconds 过期时间,0表示永不过期
|
|
620
685
|
* @return {Promise<Number>} 计算后的结果
|
|
621
686
|
*/
|
|
622
|
-
Redis.prototype.addFloat = async function
|
|
687
|
+
Redis.prototype.addFloat = async function(key, num, seconds = 0) {
|
|
623
688
|
try {
|
|
689
|
+
// 参数验证
|
|
690
|
+
if (!key || typeof key !== 'string') {
|
|
691
|
+
$.log.warn(`[Redis] addFloat: key参数必须是非空字符串`);
|
|
692
|
+
return 0;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
// 验证num参数
|
|
696
|
+
num = parseFloat(num);
|
|
697
|
+
if (isNaN(num)) {
|
|
698
|
+
$.log.warn(`[Redis] addFloat: num参数必须是有效的数值`);
|
|
699
|
+
return 0;
|
|
700
|
+
}
|
|
701
|
+
|
|
624
702
|
// 触发前置事件,允许修改或阻止操作
|
|
625
|
-
const beforeEventData = {
|
|
703
|
+
const beforeEventData = {
|
|
704
|
+
key,
|
|
705
|
+
value: num,
|
|
706
|
+
seconds,
|
|
707
|
+
cancel: false
|
|
708
|
+
};
|
|
626
709
|
this.emit('addFloat_before', beforeEventData);
|
|
627
710
|
|
|
628
711
|
// 如果事件处理器标记为取消,则返回默认值
|
|
@@ -632,57 +715,87 @@ Redis.prototype.addFloat = async function (key, num) {
|
|
|
632
715
|
}
|
|
633
716
|
|
|
634
717
|
// 使用可能被修改的值
|
|
635
|
-
let {
|
|
718
|
+
let {
|
|
719
|
+
key: finalKey,
|
|
720
|
+
value: finalNum,
|
|
721
|
+
seconds: finalSeconds
|
|
722
|
+
} = beforeEventData;
|
|
636
723
|
let result;
|
|
637
724
|
|
|
638
725
|
const connection = await this._getConnection();
|
|
639
726
|
try {
|
|
640
|
-
|
|
727
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
641
728
|
|
|
642
729
|
// 优先使用原生方法
|
|
643
730
|
if (typeof connection.incrByFloat === 'function') {
|
|
644
|
-
result = parseFloat(await connection.incrByFloat(
|
|
731
|
+
result = parseFloat(await connection.incrByFloat(prefixedKey, finalNum));
|
|
645
732
|
}
|
|
646
733
|
// 尝试使用execute通用方法
|
|
647
734
|
else if (typeof connection.execute === 'function') {
|
|
648
|
-
result = parseFloat(await connection.execute('INCRBYFLOAT', [
|
|
735
|
+
result = parseFloat(await connection.execute('INCRBYFLOAT', [prefixedKey, finalNum]));
|
|
649
736
|
}
|
|
650
737
|
// 回退方案
|
|
651
738
|
else {
|
|
652
739
|
$.log.warn(`[Redis] 连接对象不支持incrByFloat操作,使用回退方案`);
|
|
653
|
-
let value = await this.get(
|
|
740
|
+
let value = await this.get(prefixedKey);
|
|
654
741
|
let n = 0;
|
|
655
742
|
if (value) {
|
|
656
743
|
n = Number(value);
|
|
657
744
|
}
|
|
658
745
|
n += finalNum;
|
|
659
|
-
await this.set(
|
|
746
|
+
await this.set(prefixedKey, n, finalSeconds);
|
|
660
747
|
result = n;
|
|
661
748
|
}
|
|
662
749
|
|
|
750
|
+
// 设置过期时间
|
|
751
|
+
if (finalSeconds > 0) {
|
|
752
|
+
if (typeof connection.expire === 'function') {
|
|
753
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
754
|
+
} else if (typeof connection.execute === 'function') {
|
|
755
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
663
759
|
// 触发后置事件
|
|
664
|
-
this.emit('addFloat_after', {
|
|
760
|
+
this.emit('addFloat_after', {
|
|
761
|
+
key: finalKey,
|
|
762
|
+
value: finalNum,
|
|
763
|
+
seconds: finalSeconds,
|
|
764
|
+
result,
|
|
765
|
+
success: true
|
|
766
|
+
});
|
|
665
767
|
return result;
|
|
666
768
|
} catch (err) {
|
|
667
769
|
// 如果出错,回退到先获取再设置的方式
|
|
668
770
|
$.log.warn(`[Redis] 使用原子操作增加浮点数值失败,使用回退方案:`, err);
|
|
669
|
-
let value = await this.get(
|
|
771
|
+
let value = await this.get(prefixedKey);
|
|
670
772
|
let n = 0;
|
|
671
773
|
if (value) {
|
|
672
774
|
n = Number(value);
|
|
673
775
|
}
|
|
674
776
|
n += finalNum;
|
|
675
|
-
await this.set(
|
|
777
|
+
await this.set(prefixedKey, n, finalSeconds);
|
|
676
778
|
|
|
677
779
|
// 触发后置事件
|
|
678
|
-
this.emit('addFloat_after', {
|
|
780
|
+
this.emit('addFloat_after', {
|
|
781
|
+
key: finalKey,
|
|
782
|
+
value: finalNum,
|
|
783
|
+
seconds: finalSeconds,
|
|
784
|
+
result: n,
|
|
785
|
+
success: true
|
|
786
|
+
});
|
|
679
787
|
return n;
|
|
680
788
|
} finally {
|
|
681
789
|
this._recycleConnection(connection);
|
|
682
790
|
}
|
|
683
791
|
} catch (err) {
|
|
684
792
|
// 触发错误事件
|
|
685
|
-
this.emit('addFloat_error', {
|
|
793
|
+
this.emit('addFloat_error', {
|
|
794
|
+
key,
|
|
795
|
+
value: num,
|
|
796
|
+
seconds,
|
|
797
|
+
error: err
|
|
798
|
+
});
|
|
686
799
|
$.log.error(`[Redis] 增加浮点数值失败 [${key}]:`, err);
|
|
687
800
|
// 与CacheBase保持一致,错误时返回默认值而不是抛出异常
|
|
688
801
|
return 0;
|
|
@@ -690,15 +803,34 @@ Redis.prototype.addFloat = async function (key, num) {
|
|
|
690
803
|
};
|
|
691
804
|
|
|
692
805
|
/**
|
|
693
|
-
* @description
|
|
806
|
+
* @description 增加字符串值到指定缓存(兼容方法)
|
|
694
807
|
* @param {String} key 键
|
|
695
808
|
* @param {String} str 添加的字符串
|
|
809
|
+
* @param {Number} seconds 过期时间,0表示永不过期
|
|
696
810
|
* @return {Promise<Number>} 添加后的字符串长度
|
|
697
811
|
*/
|
|
698
|
-
Redis.prototype.addStr = async function
|
|
812
|
+
Redis.prototype.addStr = async function(key, str, seconds = 0) {
|
|
699
813
|
try {
|
|
814
|
+
// 参数验证
|
|
815
|
+
if (!key || typeof key !== 'string') {
|
|
816
|
+
$.log.warn(`[Redis] addStr: key参数必须是非空字符串`);
|
|
817
|
+
return 0;
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// 验证str参数
|
|
821
|
+
if (str === undefined || str === null) {
|
|
822
|
+
$.log.warn(`[Redis] addStr: str参数不能为undefined或null`);
|
|
823
|
+
return 0;
|
|
824
|
+
}
|
|
825
|
+
str = String(str);
|
|
826
|
+
|
|
700
827
|
// 触发前置事件,允许修改或阻止操作
|
|
701
|
-
const beforeEventData = {
|
|
828
|
+
const beforeEventData = {
|
|
829
|
+
key,
|
|
830
|
+
value: str,
|
|
831
|
+
seconds,
|
|
832
|
+
cancel: false
|
|
833
|
+
};
|
|
702
834
|
this.emit('addStr_before', beforeEventData);
|
|
703
835
|
|
|
704
836
|
// 如果事件处理器标记为取消,则返回0
|
|
@@ -708,63 +840,122 @@ Redis.prototype.addStr = async function (key, str) {
|
|
|
708
840
|
}
|
|
709
841
|
|
|
710
842
|
// 使用可能被修改的值
|
|
711
|
-
let {
|
|
843
|
+
let {
|
|
844
|
+
key: finalKey,
|
|
845
|
+
value: finalStr,
|
|
846
|
+
seconds: finalSeconds
|
|
847
|
+
} = beforeEventData;
|
|
712
848
|
let result;
|
|
713
849
|
|
|
714
850
|
const connection = await this._getConnection();
|
|
715
851
|
try {
|
|
716
|
-
|
|
852
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
717
853
|
|
|
718
854
|
// 优先使用原生方法
|
|
719
855
|
if (typeof connection.append === 'function') {
|
|
720
|
-
result = await connection.append(
|
|
856
|
+
result = await connection.append(prefixedKey, finalStr);
|
|
721
857
|
}
|
|
722
858
|
// 尝试使用execute通用方法
|
|
723
859
|
else if (typeof connection.execute === 'function') {
|
|
724
|
-
result = await connection.execute('APPEND', [
|
|
860
|
+
result = await connection.execute('APPEND', [prefixedKey, finalStr]);
|
|
725
861
|
}
|
|
726
862
|
// 回退方案
|
|
727
863
|
else {
|
|
728
864
|
$.log.warn(`[Redis] 连接对象不支持append操作,使用回退方案`);
|
|
729
|
-
let value = await this.get(
|
|
865
|
+
let value = await this.get(prefixedKey) || '';
|
|
730
866
|
value += finalStr;
|
|
731
|
-
await this.set(
|
|
867
|
+
await this.set(prefixedKey, value, finalSeconds);
|
|
732
868
|
result = value.length;
|
|
733
869
|
}
|
|
734
870
|
|
|
871
|
+
// 设置过期时间
|
|
872
|
+
if (finalSeconds > 0) {
|
|
873
|
+
if (typeof connection.expire === 'function') {
|
|
874
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
875
|
+
} else if (typeof connection.execute === 'function') {
|
|
876
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
|
|
735
880
|
// 触发后置事件
|
|
736
|
-
this.emit('addStr_after', {
|
|
881
|
+
this.emit('addStr_after', {
|
|
882
|
+
key: finalKey,
|
|
883
|
+
value: finalStr,
|
|
884
|
+
seconds: finalSeconds,
|
|
885
|
+
result,
|
|
886
|
+
success: true
|
|
887
|
+
});
|
|
737
888
|
return result;
|
|
738
889
|
} catch (err) {
|
|
739
890
|
$.log.error('[Redis] 追加字符串失败:', err);
|
|
740
891
|
// 回退方案:先获取再设置
|
|
741
|
-
let value = await this.get(
|
|
892
|
+
let value = await this.get(prefixedKey) || '';
|
|
742
893
|
value += finalStr;
|
|
743
|
-
await this.set(
|
|
894
|
+
await this.set(prefixedKey, value, finalSeconds);
|
|
744
895
|
|
|
745
896
|
// 触发后置事件
|
|
746
|
-
this.emit('addStr_after', {
|
|
897
|
+
this.emit('addStr_after', {
|
|
898
|
+
key: finalKey,
|
|
899
|
+
value: finalStr,
|
|
900
|
+
seconds: finalSeconds,
|
|
901
|
+
result: value.length,
|
|
902
|
+
success: true
|
|
903
|
+
});
|
|
747
904
|
return value.length;
|
|
748
905
|
} finally {
|
|
749
906
|
this._recycleConnection(connection);
|
|
750
907
|
}
|
|
751
908
|
} catch (err) {
|
|
752
909
|
// 触发错误事件
|
|
753
|
-
this.emit('addStr_error', {
|
|
910
|
+
this.emit('addStr_error', {
|
|
911
|
+
key,
|
|
912
|
+
value: str,
|
|
913
|
+
seconds,
|
|
914
|
+
error: err
|
|
915
|
+
});
|
|
754
916
|
$.log.error(`[Redis] 追加字符串失败 [${key}]:`, err);
|
|
755
917
|
return 0;
|
|
756
918
|
}
|
|
757
919
|
};
|
|
758
920
|
|
|
759
921
|
/**
|
|
760
|
-
* @description
|
|
922
|
+
* @description 删除缓存(兼容方法)
|
|
761
923
|
* @param {String|Array<String>} key 键或键数组
|
|
762
924
|
* @return {Promise<Boolean>} 成功返回true,失败返回false
|
|
763
925
|
*/
|
|
764
|
-
Redis.prototype.del = async function
|
|
926
|
+
Redis.prototype.del = async function(key) {
|
|
765
927
|
try {
|
|
928
|
+
// 键名必须是非空字符串或非空字符串数组
|
|
929
|
+
if (!key) {
|
|
930
|
+
$.log.warn('[Redis] del: key必须是非空字符串或非空字符串数组');
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// 如果是单个键,验证是否为非空字符串
|
|
935
|
+
if (typeof key === 'string') {
|
|
936
|
+
if (!key) {
|
|
937
|
+
$.log.warn('[Redis] del: key必须是非空字符串');
|
|
938
|
+
return false;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
// 如果是数组,验证每个元素是否为非空字符串
|
|
942
|
+
else if (Array.isArray(key)) {
|
|
943
|
+
for (const k of key) {
|
|
944
|
+
if (!k || typeof k !== 'string') {
|
|
945
|
+
$.log.warn('[Redis] del: key必须是非空字符串或非空字符串数组');
|
|
946
|
+
return false;
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
} else {
|
|
950
|
+
$.log.warn('[Redis] del: key必须是非空字符串或非空字符串数组');
|
|
951
|
+
return false;
|
|
952
|
+
}
|
|
953
|
+
|
|
766
954
|
// 触发前置事件,允许修改或阻止操作
|
|
767
|
-
const beforeEventData = {
|
|
955
|
+
const beforeEventData = {
|
|
956
|
+
key,
|
|
957
|
+
cancel: false
|
|
958
|
+
};
|
|
768
959
|
this.emit('del_before', beforeEventData);
|
|
769
960
|
|
|
770
961
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -774,7 +965,9 @@ Redis.prototype.del = async function (key) {
|
|
|
774
965
|
}
|
|
775
966
|
|
|
776
967
|
// 使用可能被修改的值
|
|
777
|
-
let {
|
|
968
|
+
let {
|
|
969
|
+
key: finalKey
|
|
970
|
+
} = beforeEventData;
|
|
778
971
|
|
|
779
972
|
const connection = await this._getConnection();
|
|
780
973
|
try {
|
|
@@ -793,14 +986,22 @@ Redis.prototype.del = async function (key) {
|
|
|
793
986
|
}
|
|
794
987
|
}
|
|
795
988
|
// 触发后置事件
|
|
796
|
-
this.emit('del_after', {
|
|
989
|
+
this.emit('del_after', {
|
|
990
|
+
key: finalKey,
|
|
991
|
+
success,
|
|
992
|
+
deleted
|
|
993
|
+
});
|
|
797
994
|
} else {
|
|
798
995
|
// 单个删除
|
|
799
996
|
const prefixedKey = this.applyPrefix(finalKey);
|
|
800
997
|
const n = await connection.del(prefixedKey);
|
|
801
998
|
success = n === 1;
|
|
802
999
|
// 触发后置事件
|
|
803
|
-
this.emit('del_after', {
|
|
1000
|
+
this.emit('del_after', {
|
|
1001
|
+
key: finalKey,
|
|
1002
|
+
success,
|
|
1003
|
+
deleted: success ? [finalKey] : []
|
|
1004
|
+
});
|
|
804
1005
|
}
|
|
805
1006
|
return success;
|
|
806
1007
|
} finally {
|
|
@@ -808,8 +1009,11 @@ Redis.prototype.del = async function (key) {
|
|
|
808
1009
|
}
|
|
809
1010
|
} catch (err) {
|
|
810
1011
|
// 触发错误事件
|
|
811
|
-
this.emit('del_error', {
|
|
812
|
-
|
|
1012
|
+
this.emit('del_error', {
|
|
1013
|
+
key,
|
|
1014
|
+
error: err
|
|
1015
|
+
});
|
|
1016
|
+
$.log.error(`[Redis] 删除缓存失败 [${key}]:`, err);
|
|
813
1017
|
return false;
|
|
814
1018
|
}
|
|
815
1019
|
};
|
|
@@ -821,10 +1025,28 @@ Redis.prototype.del = async function (key) {
|
|
|
821
1025
|
* @param {Number} seconds 秒
|
|
822
1026
|
* @return {Promise<Boolean>} 操作结果
|
|
823
1027
|
*/
|
|
824
|
-
|
|
1028
|
+
/**
|
|
1029
|
+
* @description 设置缓存(兼容方法)
|
|
1030
|
+
* @param {String} key 键
|
|
1031
|
+
* @param {*} value 值
|
|
1032
|
+
* @param {Number} seconds 过期时间,0表示永不过期
|
|
1033
|
+
* @return {Promise<Boolean>} 成功返回true,失败返回false
|
|
1034
|
+
*/
|
|
1035
|
+
Redis.prototype.set = async function(key, value, seconds = 0) {
|
|
825
1036
|
try {
|
|
1037
|
+
// 键名必须是非空字符串
|
|
1038
|
+
if (!key || typeof key !== 'string') {
|
|
1039
|
+
$.log.error('[Redis] 参数错误: key必须是非空字符串');
|
|
1040
|
+
return false;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
826
1043
|
// 触发前置事件,允许修改或阻止操作
|
|
827
|
-
const beforeEventData = {
|
|
1044
|
+
const beforeEventData = {
|
|
1045
|
+
key,
|
|
1046
|
+
value,
|
|
1047
|
+
seconds,
|
|
1048
|
+
cancel: false
|
|
1049
|
+
};
|
|
828
1050
|
this.emit('set_before', beforeEventData);
|
|
829
1051
|
|
|
830
1052
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -834,25 +1056,34 @@ Redis.prototype.set = async function (key, value, seconds) {
|
|
|
834
1056
|
}
|
|
835
1057
|
|
|
836
1058
|
// 使用可能被修改的值
|
|
837
|
-
let {
|
|
1059
|
+
let {
|
|
1060
|
+
key: finalKey,
|
|
1061
|
+
value: finalValue,
|
|
1062
|
+
seconds: finalSeconds
|
|
1063
|
+
} = beforeEventData;
|
|
838
1064
|
|
|
839
1065
|
const connection = await this._getConnection();
|
|
840
1066
|
try {
|
|
841
|
-
|
|
842
|
-
if (typeof
|
|
1067
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
1068
|
+
if (typeof(finalValue) === "object") {
|
|
843
1069
|
finalValue = JSON.stringify(finalValue);
|
|
844
1070
|
}
|
|
845
1071
|
|
|
846
|
-
if (finalSeconds) {
|
|
847
|
-
await connection.set(
|
|
1072
|
+
if (finalSeconds > 0) {
|
|
1073
|
+
await connection.set(prefixedKey, finalValue, {
|
|
848
1074
|
EX: finalSeconds
|
|
849
1075
|
});
|
|
850
1076
|
} else {
|
|
851
|
-
await connection.set(
|
|
1077
|
+
await connection.set(prefixedKey, finalValue);
|
|
852
1078
|
}
|
|
853
1079
|
|
|
854
1080
|
// 触发后置事件
|
|
855
|
-
this.emit('set_after', {
|
|
1081
|
+
this.emit('set_after', {
|
|
1082
|
+
key,
|
|
1083
|
+
value,
|
|
1084
|
+
seconds,
|
|
1085
|
+
success: true
|
|
1086
|
+
});
|
|
856
1087
|
return true;
|
|
857
1088
|
} finally {
|
|
858
1089
|
this._recycleConnection(connection);
|
|
@@ -860,7 +1091,12 @@ Redis.prototype.set = async function (key, value, seconds) {
|
|
|
860
1091
|
} catch (err) {
|
|
861
1092
|
$.log.error(`[Redis] 设置缓存失败 [${key}]:`, err);
|
|
862
1093
|
// 触发错误事件
|
|
863
|
-
this.emit('set_error', {
|
|
1094
|
+
this.emit('set_error', {
|
|
1095
|
+
key,
|
|
1096
|
+
value,
|
|
1097
|
+
seconds,
|
|
1098
|
+
error: err
|
|
1099
|
+
});
|
|
864
1100
|
return false;
|
|
865
1101
|
}
|
|
866
1102
|
};
|
|
@@ -869,13 +1105,18 @@ Redis.prototype.set = async function (key, value, seconds) {
|
|
|
869
1105
|
* @description 仅当键不存在时设置缓存
|
|
870
1106
|
* @param {String} key 键
|
|
871
1107
|
* @param {Object} value 值
|
|
872
|
-
* @param {Number} seconds
|
|
873
|
-
* @return {Promise<Boolean>}
|
|
1108
|
+
* @param {Number} seconds 过期时间(秒)
|
|
1109
|
+
* @return {Promise<Boolean>} 操作结果,键不存在时设置成功返回true,键已存在返回false
|
|
874
1110
|
*/
|
|
875
|
-
Redis.prototype.add = async function
|
|
1111
|
+
Redis.prototype.add = async function(key, value, seconds) {
|
|
876
1112
|
try {
|
|
877
1113
|
// 触发前置事件,允许修改或阻止操作
|
|
878
|
-
const beforeEventData = {
|
|
1114
|
+
const beforeEventData = {
|
|
1115
|
+
key,
|
|
1116
|
+
value,
|
|
1117
|
+
ttl: seconds,
|
|
1118
|
+
cancel: false
|
|
1119
|
+
};
|
|
879
1120
|
this.emit('add_before', beforeEventData);
|
|
880
1121
|
|
|
881
1122
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -885,21 +1126,36 @@ Redis.prototype.add = async function (key, value, seconds) {
|
|
|
885
1126
|
}
|
|
886
1127
|
|
|
887
1128
|
// 使用可能被修改的值
|
|
888
|
-
let {
|
|
1129
|
+
let {
|
|
1130
|
+
key: finalKey,
|
|
1131
|
+
value: finalValue,
|
|
1132
|
+
ttl: finalSeconds
|
|
1133
|
+
} = beforeEventData;
|
|
889
1134
|
|
|
890
1135
|
const connection = await this._getConnection();
|
|
891
1136
|
try {
|
|
892
1137
|
finalKey = this.applyPrefix(finalKey);
|
|
893
|
-
if (typeof
|
|
1138
|
+
if (typeof(finalValue) === "object") {
|
|
894
1139
|
finalValue = JSON.stringify(finalValue);
|
|
895
1140
|
}
|
|
896
1141
|
|
|
897
|
-
|
|
1142
|
+
// 使用NX选项实现SETNX操作 - 仅在键不存在时设置
|
|
1143
|
+
const options = finalSeconds ? {
|
|
1144
|
+
NX: true,
|
|
1145
|
+
EX: finalSeconds
|
|
1146
|
+
} : {
|
|
1147
|
+
NX: true
|
|
1148
|
+
};
|
|
898
1149
|
const result = await connection.set(finalKey, finalValue, options);
|
|
899
1150
|
const success = result === "OK";
|
|
900
1151
|
|
|
901
1152
|
// 触发后置事件
|
|
902
|
-
this.emit('add_after', {
|
|
1153
|
+
this.emit('add_after', {
|
|
1154
|
+
key: finalKey,
|
|
1155
|
+
value: finalValue,
|
|
1156
|
+
ttl: finalSeconds,
|
|
1157
|
+
success
|
|
1158
|
+
});
|
|
903
1159
|
return success;
|
|
904
1160
|
} finally {
|
|
905
1161
|
this._recycleConnection(connection);
|
|
@@ -907,7 +1163,12 @@ Redis.prototype.add = async function (key, value, seconds) {
|
|
|
907
1163
|
} catch (err) {
|
|
908
1164
|
$.log.error(`[Redis] 添加缓存失败 [${key}]:`, err);
|
|
909
1165
|
// 触发错误事件
|
|
910
|
-
this.emit('add_error', {
|
|
1166
|
+
this.emit('add_error', {
|
|
1167
|
+
key,
|
|
1168
|
+
value,
|
|
1169
|
+
ttl: seconds,
|
|
1170
|
+
error: err
|
|
1171
|
+
});
|
|
911
1172
|
return false;
|
|
912
1173
|
}
|
|
913
1174
|
};
|
|
@@ -917,70 +1178,208 @@ Redis.prototype.add = async function (key, value, seconds) {
|
|
|
917
1178
|
* @param {String} key 键
|
|
918
1179
|
* @return {Promise<Object>} 查询值
|
|
919
1180
|
*/
|
|
920
|
-
|
|
1181
|
+
/**
|
|
1182
|
+
* @description 获取缓存(兼容方法)
|
|
1183
|
+
* @param {String} key 键
|
|
1184
|
+
* @return {Promise<*>} 获取到的值,不存在时返回null
|
|
1185
|
+
*/
|
|
1186
|
+
Redis.prototype.get = async function(key) {
|
|
921
1187
|
try {
|
|
1188
|
+
// 参数验证
|
|
1189
|
+
if (!key || typeof key !== 'string') {
|
|
1190
|
+
$.log.warn(`[Redis] get: key参数必须是非空字符串`);
|
|
1191
|
+
return null;
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// 触发前置事件,允许修改或阻止操作
|
|
1195
|
+
const beforeEventData = {
|
|
1196
|
+
key,
|
|
1197
|
+
cancel: false
|
|
1198
|
+
};
|
|
1199
|
+
this.emit('get_before', beforeEventData);
|
|
1200
|
+
|
|
1201
|
+
// 如果事件处理器标记为取消,则返回null
|
|
1202
|
+
if (beforeEventData.cancel) {
|
|
1203
|
+
$.log.debug(`[Redis] get操作被事件处理器取消 [${key}]`);
|
|
1204
|
+
return null;
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
// 使用可能被修改的值
|
|
1208
|
+
const finalKey = beforeEventData.key;
|
|
1209
|
+
|
|
922
1210
|
const connection = await this._getConnection();
|
|
923
1211
|
try {
|
|
924
|
-
|
|
925
|
-
const value = await connection.get(
|
|
926
|
-
|
|
1212
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
1213
|
+
const value = await connection.get(prefixedKey);
|
|
1214
|
+
let result = value;
|
|
1215
|
+
if (typeof(value) === "string") {
|
|
927
1216
|
// 尝试解析JSON
|
|
928
1217
|
try {
|
|
929
1218
|
if (value.startsWith("{") && value.endsWith("}") ||
|
|
930
1219
|
value.startsWith("[") && value.endsWith("]")) {
|
|
931
|
-
|
|
1220
|
+
result = JSON.parse(value);
|
|
932
1221
|
}
|
|
933
1222
|
} catch (e) {
|
|
934
1223
|
// 解析失败,返回原始字符串
|
|
935
1224
|
}
|
|
936
1225
|
}
|
|
937
|
-
|
|
1226
|
+
|
|
1227
|
+
// 触发后置事件
|
|
1228
|
+
this.emit('get_after', {
|
|
1229
|
+
key: finalKey,
|
|
1230
|
+
value: result,
|
|
1231
|
+
success: true
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
return result;
|
|
938
1235
|
} finally {
|
|
939
1236
|
this._recycleConnection(connection);
|
|
940
1237
|
}
|
|
941
1238
|
} catch (err) {
|
|
1239
|
+
// 触发错误事件
|
|
1240
|
+
this.emit('get_error', {
|
|
1241
|
+
key,
|
|
1242
|
+
error: err
|
|
1243
|
+
});
|
|
942
1244
|
$.log.error(`[Redis] 获取缓存失败 [${key}]:`, err);
|
|
943
1245
|
return null;
|
|
944
1246
|
}
|
|
945
1247
|
};
|
|
946
1248
|
|
|
947
1249
|
/**
|
|
948
|
-
* @description
|
|
1250
|
+
* @description 判断键是否存在(兼容方法)
|
|
949
1251
|
* @param {String} key 键
|
|
950
1252
|
* @return {Promise<Boolean>} 有返回true, 没有返回false
|
|
951
1253
|
*/
|
|
952
|
-
Redis.prototype.has = async function
|
|
1254
|
+
Redis.prototype.has = async function(key) {
|
|
953
1255
|
try {
|
|
1256
|
+
// 参数验证
|
|
1257
|
+
if (!key || typeof key !== 'string') {
|
|
1258
|
+
$.log.warn(`[Redis] has: key参数必须是非空字符串`);
|
|
1259
|
+
return false;
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// 触发前置事件,允许修改或阻止操作
|
|
1263
|
+
const beforeEventData = {
|
|
1264
|
+
key,
|
|
1265
|
+
cancel: false
|
|
1266
|
+
};
|
|
1267
|
+
this.emit('has_before', beforeEventData);
|
|
1268
|
+
|
|
1269
|
+
// 如果事件处理器标记为取消,则返回false
|
|
1270
|
+
if (beforeEventData.cancel) {
|
|
1271
|
+
$.log.debug(`[Redis] has操作被事件处理器取消 [${key}]`);
|
|
1272
|
+
return false;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
// 使用可能被修改的值
|
|
1276
|
+
const finalKey = beforeEventData.key;
|
|
1277
|
+
|
|
954
1278
|
const connection = await this._getConnection();
|
|
955
1279
|
try {
|
|
956
|
-
|
|
957
|
-
const result = await connection.exists(
|
|
958
|
-
|
|
1280
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
1281
|
+
const result = await connection.exists(prefixedKey);
|
|
1282
|
+
const exists = result > 0;
|
|
1283
|
+
|
|
1284
|
+
// 触发后置事件
|
|
1285
|
+
this.emit('has_after', {
|
|
1286
|
+
key: finalKey,
|
|
1287
|
+
result: exists,
|
|
1288
|
+
success: true
|
|
1289
|
+
});
|
|
1290
|
+
|
|
1291
|
+
return exists;
|
|
959
1292
|
} finally {
|
|
960
1293
|
this._recycleConnection(connection);
|
|
961
1294
|
}
|
|
962
1295
|
} catch (err) {
|
|
1296
|
+
// 触发错误事件
|
|
1297
|
+
this.emit('has_error', {
|
|
1298
|
+
key,
|
|
1299
|
+
error: err
|
|
1300
|
+
});
|
|
963
1301
|
$.log.error(`[Redis] 检查键是否存在失败 [${key}]:`, err);
|
|
964
1302
|
return false;
|
|
965
1303
|
}
|
|
966
1304
|
};
|
|
967
1305
|
|
|
968
1306
|
/**
|
|
969
|
-
* @description
|
|
970
|
-
* @param {String} key
|
|
1307
|
+
* @description 检查键是否存在,返回存在的键数量(兼容方法)
|
|
1308
|
+
* @param {String|Array<String>} key 键或键数组
|
|
971
1309
|
* @return {Promise<Number>} 存在的键数量
|
|
972
1310
|
*/
|
|
973
|
-
Redis.prototype.exists = async function
|
|
1311
|
+
Redis.prototype.exists = async function(key) {
|
|
974
1312
|
try {
|
|
1313
|
+
// 参数验证
|
|
1314
|
+
if (!key) {
|
|
1315
|
+
$.log.warn('[Redis] exists: key必须是非空字符串或非空字符串数组');
|
|
1316
|
+
return 0;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// 如果是单个键,验证是否为非空字符串
|
|
1320
|
+
if (typeof key === 'string') {
|
|
1321
|
+
if (!key) {
|
|
1322
|
+
$.log.warn('[Redis] exists: key必须是非空字符串');
|
|
1323
|
+
return 0;
|
|
1324
|
+
}
|
|
1325
|
+
}
|
|
1326
|
+
// 如果是数组,验证每个元素是否为非空字符串
|
|
1327
|
+
else if (Array.isArray(key)) {
|
|
1328
|
+
for (const k of key) {
|
|
1329
|
+
if (!k || typeof k !== 'string') {
|
|
1330
|
+
$.log.warn('[Redis] exists: key必须是非空字符串或非空字符串数组');
|
|
1331
|
+
return 0;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
} else {
|
|
1335
|
+
$.log.warn('[Redis] exists: key必须是非空字符串或非空字符串数组');
|
|
1336
|
+
return 0;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
// 触发前置事件,允许修改或阻止操作
|
|
1340
|
+
const beforeEventData = {
|
|
1341
|
+
key,
|
|
1342
|
+
cancel: false
|
|
1343
|
+
};
|
|
1344
|
+
this.emit('exists_before', beforeEventData);
|
|
1345
|
+
|
|
1346
|
+
// 如果事件处理器标记为取消,则返回0
|
|
1347
|
+
if (beforeEventData.cancel) {
|
|
1348
|
+
$.log.debug(`[Redis] exists操作被事件处理器取消 [${key}]`);
|
|
1349
|
+
return 0;
|
|
1350
|
+
}
|
|
1351
|
+
|
|
1352
|
+
// 使用可能被修改的值
|
|
1353
|
+
const finalKey = beforeEventData.key;
|
|
1354
|
+
|
|
975
1355
|
const connection = await this._getConnection();
|
|
976
1356
|
try {
|
|
977
|
-
|
|
978
|
-
|
|
1357
|
+
let result;
|
|
1358
|
+
if (typeof finalKey === 'string') {
|
|
1359
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
1360
|
+
result = await connection.exists(prefixedKey);
|
|
1361
|
+
} else if (Array.isArray(finalKey)) {
|
|
1362
|
+
const prefixedKeys = finalKey.map(k => this.applyPrefix(k));
|
|
1363
|
+
result = await connection.exists(...prefixedKeys);
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
// 触发后置事件
|
|
1367
|
+
this.emit('exists_after', {
|
|
1368
|
+
key: finalKey,
|
|
1369
|
+
result,
|
|
1370
|
+
success: true
|
|
1371
|
+
});
|
|
1372
|
+
|
|
979
1373
|
return result;
|
|
980
1374
|
} finally {
|
|
981
1375
|
this._recycleConnection(connection);
|
|
982
1376
|
}
|
|
983
1377
|
} catch (err) {
|
|
1378
|
+
// 触发错误事件
|
|
1379
|
+
this.emit('exists_error', {
|
|
1380
|
+
key,
|
|
1381
|
+
error: err
|
|
1382
|
+
});
|
|
984
1383
|
$.log.error(`[Redis] 检查键存在性失败 [${key}]:`, err);
|
|
985
1384
|
return 0;
|
|
986
1385
|
}
|
|
@@ -993,7 +1392,7 @@ Redis.prototype.exists = async function (key) {
|
|
|
993
1392
|
* @param {Number} end 结束位置
|
|
994
1393
|
* @return {Promise<String>} 查询值
|
|
995
1394
|
*/
|
|
996
|
-
Redis.prototype.getrange = async function
|
|
1395
|
+
Redis.prototype.getrange = async function(key, start, end) {
|
|
997
1396
|
try {
|
|
998
1397
|
const connection = await this._getConnection();
|
|
999
1398
|
try {
|
|
@@ -1023,7 +1422,7 @@ Redis.prototype.getrange = async function (key, start, end) {
|
|
|
1023
1422
|
* @param {String} str_sub 插入的字符串
|
|
1024
1423
|
* @return {String} 插入后的字符串
|
|
1025
1424
|
*/
|
|
1026
|
-
Redis.prototype.insertString = function
|
|
1425
|
+
Redis.prototype.insertString = function(str, index, str_sub) {
|
|
1027
1426
|
return str.substring(0, index) + str_sub + str.substring(index);
|
|
1028
1427
|
};
|
|
1029
1428
|
|
|
@@ -1034,10 +1433,15 @@ Redis.prototype.insertString = function (str, index, str_sub) {
|
|
|
1034
1433
|
* @param {String} value 变更的值
|
|
1035
1434
|
* @return {Promise<Number>} 字符串长度
|
|
1036
1435
|
*/
|
|
1037
|
-
Redis.prototype.setrange = async function
|
|
1436
|
+
Redis.prototype.setrange = async function(key, index, value) {
|
|
1038
1437
|
try {
|
|
1039
1438
|
// 触发前置事件,允许修改或阻止操作
|
|
1040
|
-
const beforeEventData = {
|
|
1439
|
+
const beforeEventData = {
|
|
1440
|
+
key,
|
|
1441
|
+
index,
|
|
1442
|
+
value,
|
|
1443
|
+
cancel: false
|
|
1444
|
+
};
|
|
1041
1445
|
this.emit('setrange_before', beforeEventData);
|
|
1042
1446
|
|
|
1043
1447
|
// 如果事件处理器标记为取消,则返回0
|
|
@@ -1047,7 +1451,11 @@ Redis.prototype.setrange = async function (key, index, value) {
|
|
|
1047
1451
|
}
|
|
1048
1452
|
|
|
1049
1453
|
// 使用可能被修改的值
|
|
1050
|
-
let {
|
|
1454
|
+
let {
|
|
1455
|
+
key: finalKey,
|
|
1456
|
+
index: finalIndex,
|
|
1457
|
+
value: finalValue
|
|
1458
|
+
} = beforeEventData;
|
|
1051
1459
|
let result;
|
|
1052
1460
|
|
|
1053
1461
|
const connection = await this._getConnection();
|
|
@@ -1076,7 +1484,13 @@ Redis.prototype.setrange = async function (key, index, value) {
|
|
|
1076
1484
|
}
|
|
1077
1485
|
|
|
1078
1486
|
// 触发后置事件
|
|
1079
|
-
this.emit('setrange_after', {
|
|
1487
|
+
this.emit('setrange_after', {
|
|
1488
|
+
key: finalKey,
|
|
1489
|
+
index: finalIndex,
|
|
1490
|
+
value: finalValue,
|
|
1491
|
+
result,
|
|
1492
|
+
success: true
|
|
1493
|
+
});
|
|
1080
1494
|
return result;
|
|
1081
1495
|
} catch (err) {
|
|
1082
1496
|
$.log.error('[Redis] 设置字符串范围失败:', err);
|
|
@@ -1090,14 +1504,25 @@ Redis.prototype.setrange = async function (key, index, value) {
|
|
|
1090
1504
|
await this.set(finalKey, str);
|
|
1091
1505
|
|
|
1092
1506
|
// 触发后置事件
|
|
1093
|
-
this.emit('setrange_after', {
|
|
1507
|
+
this.emit('setrange_after', {
|
|
1508
|
+
key: finalKey,
|
|
1509
|
+
index: finalIndex,
|
|
1510
|
+
value: finalValue,
|
|
1511
|
+
result: str.length,
|
|
1512
|
+
success: true
|
|
1513
|
+
});
|
|
1094
1514
|
return str.length;
|
|
1095
1515
|
} finally {
|
|
1096
1516
|
this._recycleConnection(connection);
|
|
1097
1517
|
}
|
|
1098
1518
|
} catch (err) {
|
|
1099
1519
|
// 触发错误事件
|
|
1100
|
-
this.emit('setrange_error', {
|
|
1520
|
+
this.emit('setrange_error', {
|
|
1521
|
+
key,
|
|
1522
|
+
index,
|
|
1523
|
+
value,
|
|
1524
|
+
error: err
|
|
1525
|
+
});
|
|
1101
1526
|
$.log.error(`[Redis] 设置字符串范围失败 [${key}]:`, err);
|
|
1102
1527
|
return 0;
|
|
1103
1528
|
}
|
|
@@ -1108,10 +1533,13 @@ Redis.prototype.setrange = async function (key, index, value) {
|
|
|
1108
1533
|
* @param {String} key 键, 为空则清空所有
|
|
1109
1534
|
* @return {Promise<Boolean>} 执行结果
|
|
1110
1535
|
*/
|
|
1111
|
-
Redis.prototype.clear = async function
|
|
1536
|
+
Redis.prototype.clear = async function(key) {
|
|
1112
1537
|
try {
|
|
1113
1538
|
// 触发前置事件,允许修改或阻止操作
|
|
1114
|
-
const beforeEventData = {
|
|
1539
|
+
const beforeEventData = {
|
|
1540
|
+
key,
|
|
1541
|
+
cancel: false
|
|
1542
|
+
};
|
|
1115
1543
|
this.emit('clear_before', beforeEventData);
|
|
1116
1544
|
|
|
1117
1545
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -1121,7 +1549,9 @@ Redis.prototype.clear = async function (key) {
|
|
|
1121
1549
|
}
|
|
1122
1550
|
|
|
1123
1551
|
// 使用可能被修改的值
|
|
1124
|
-
let {
|
|
1552
|
+
let {
|
|
1553
|
+
key: finalKey
|
|
1554
|
+
} = beforeEventData;
|
|
1125
1555
|
let success = false;
|
|
1126
1556
|
|
|
1127
1557
|
const connection = await this._getConnection();
|
|
@@ -1144,14 +1574,20 @@ Redis.prototype.clear = async function (key) {
|
|
|
1144
1574
|
}
|
|
1145
1575
|
|
|
1146
1576
|
// 触发后置事件
|
|
1147
|
-
this.emit('clear_after', {
|
|
1577
|
+
this.emit('clear_after', {
|
|
1578
|
+
key: finalKey,
|
|
1579
|
+
success
|
|
1580
|
+
});
|
|
1148
1581
|
return success;
|
|
1149
1582
|
} finally {
|
|
1150
1583
|
this._recycleConnection(connection);
|
|
1151
1584
|
}
|
|
1152
1585
|
} catch (err) {
|
|
1153
1586
|
// 触发错误事件
|
|
1154
|
-
this.emit('clear_error', {
|
|
1587
|
+
this.emit('clear_error', {
|
|
1588
|
+
key,
|
|
1589
|
+
error: err
|
|
1590
|
+
});
|
|
1155
1591
|
$.log.error('[Redis] 清空缓存失败:', err);
|
|
1156
1592
|
return false;
|
|
1157
1593
|
}
|
|
@@ -1163,7 +1599,7 @@ Redis.prototype.clear = async function (key) {
|
|
|
1163
1599
|
* @param {Object} options 排序选项
|
|
1164
1600
|
* @return {Promise<Array>} 排序后的数组
|
|
1165
1601
|
*/
|
|
1166
|
-
Redis.prototype.sort = async function
|
|
1602
|
+
Redis.prototype.sort = async function(key, options = {}) {
|
|
1167
1603
|
try {
|
|
1168
1604
|
const connection = await this._getConnection();
|
|
1169
1605
|
try {
|
|
@@ -1198,7 +1634,7 @@ Redis.prototype.sort = async function (key, options = {}) {
|
|
|
1198
1634
|
} catch (err) {
|
|
1199
1635
|
$.log.error('[Redis] 排序失败:', err);
|
|
1200
1636
|
// 回退方案:获取数据后在内存中排序
|
|
1201
|
-
const data = await this.
|
|
1637
|
+
const data = await this.getForList(key);
|
|
1202
1638
|
return data.sort((a, b) => {
|
|
1203
1639
|
if (options.alpha) {
|
|
1204
1640
|
return options.order === 'desc' ? b.localeCompare(a) : a.localeCompare(b);
|
|
@@ -1220,7 +1656,7 @@ Redis.prototype.sort = async function (key, options = {}) {
|
|
|
1220
1656
|
* @param {String} pattern 键模式 支持*号
|
|
1221
1657
|
* @return {Promise<Array>} 键数组
|
|
1222
1658
|
*/
|
|
1223
|
-
Redis.prototype.keys = async function
|
|
1659
|
+
Redis.prototype.keys = async function(pattern = '*') {
|
|
1224
1660
|
try {
|
|
1225
1661
|
const connection = await this._getConnection();
|
|
1226
1662
|
try {
|
|
@@ -1245,20 +1681,29 @@ Redis.prototype.keys = async function (pattern = '*') {
|
|
|
1245
1681
|
* @param {Number} seconds 秒
|
|
1246
1682
|
* @return {Promise<Number>} 数组长度
|
|
1247
1683
|
*/
|
|
1248
|
-
Redis.prototype.
|
|
1684
|
+
Redis.prototype.setForList = async function(key, value, seconds) {
|
|
1249
1685
|
try {
|
|
1250
1686
|
// 触发前置事件,允许修改或阻止操作
|
|
1251
|
-
const beforeEventData = {
|
|
1252
|
-
|
|
1687
|
+
const beforeEventData = {
|
|
1688
|
+
key,
|
|
1689
|
+
value,
|
|
1690
|
+
ttl: seconds,
|
|
1691
|
+
cancel: false
|
|
1692
|
+
};
|
|
1693
|
+
this.emit('setForList_before', beforeEventData);
|
|
1253
1694
|
|
|
1254
1695
|
// 如果事件处理器标记为取消,则返回0
|
|
1255
1696
|
if (beforeEventData.cancel) {
|
|
1256
|
-
$.log.debug(`[Redis]
|
|
1697
|
+
$.log.debug(`[Redis] setForList操作被事件处理器取消 [${key}]`);
|
|
1257
1698
|
return 0;
|
|
1258
1699
|
}
|
|
1259
1700
|
|
|
1260
1701
|
// 使用可能被修改的值
|
|
1261
|
-
let {
|
|
1702
|
+
let {
|
|
1703
|
+
key: finalKey,
|
|
1704
|
+
value: finalValue,
|
|
1705
|
+
ttl: finalSeconds
|
|
1706
|
+
} = beforeEventData;
|
|
1262
1707
|
let len = 0;
|
|
1263
1708
|
|
|
1264
1709
|
const connection = await this._getConnection();
|
|
@@ -1306,14 +1751,24 @@ Redis.prototype.list_set = async function (key, value, seconds) {
|
|
|
1306
1751
|
}
|
|
1307
1752
|
|
|
1308
1753
|
// 触发后置事件
|
|
1309
|
-
this.emit('
|
|
1754
|
+
this.emit('setForList_after', {
|
|
1755
|
+
key: finalKey,
|
|
1756
|
+
value: finalValue,
|
|
1757
|
+
ttl: finalSeconds,
|
|
1758
|
+
result: len,
|
|
1759
|
+
success: len > 0
|
|
1760
|
+
});
|
|
1310
1761
|
return len;
|
|
1311
1762
|
} finally {
|
|
1312
1763
|
this._recycleConnection(connection);
|
|
1313
1764
|
}
|
|
1314
1765
|
} catch (err) {
|
|
1315
1766
|
// 触发错误事件
|
|
1316
|
-
this.emit('
|
|
1767
|
+
this.emit('setForList_error', {
|
|
1768
|
+
key,
|
|
1769
|
+
value,
|
|
1770
|
+
error: err
|
|
1771
|
+
});
|
|
1317
1772
|
$.log.error(`[Redis] 设置列表失败 [${key}]:`, err);
|
|
1318
1773
|
return 0;
|
|
1319
1774
|
}
|
|
@@ -1325,10 +1780,14 @@ Redis.prototype.list_set = async function (key, value, seconds) {
|
|
|
1325
1780
|
* @param {Object|Array} value 值
|
|
1326
1781
|
* @return {Promise<Number>} 追加后的数组长度
|
|
1327
1782
|
*/
|
|
1328
|
-
Redis.prototype.list_push = async function
|
|
1783
|
+
Redis.prototype.list_push = async function(key, value) {
|
|
1329
1784
|
try {
|
|
1330
1785
|
// 触发前置事件,允许修改或阻止操作
|
|
1331
|
-
const beforeEventData = {
|
|
1786
|
+
const beforeEventData = {
|
|
1787
|
+
key,
|
|
1788
|
+
value,
|
|
1789
|
+
cancel: false
|
|
1790
|
+
};
|
|
1332
1791
|
this.emit('list_push_before', beforeEventData);
|
|
1333
1792
|
|
|
1334
1793
|
// 如果事件处理器标记为取消,则返回0
|
|
@@ -1338,7 +1797,10 @@ Redis.prototype.list_push = async function (key, value) {
|
|
|
1338
1797
|
}
|
|
1339
1798
|
|
|
1340
1799
|
// 使用可能被修改的值
|
|
1341
|
-
let {
|
|
1800
|
+
let {
|
|
1801
|
+
key: finalKey,
|
|
1802
|
+
value: finalValue
|
|
1803
|
+
} = beforeEventData;
|
|
1342
1804
|
let len = 0;
|
|
1343
1805
|
let success = true;
|
|
1344
1806
|
|
|
@@ -1371,181 +1833,291 @@ Redis.prototype.list_push = async function (key, value) {
|
|
|
1371
1833
|
}
|
|
1372
1834
|
|
|
1373
1835
|
// 触发后置事件
|
|
1374
|
-
this.emit('list_push_after', {
|
|
1836
|
+
this.emit('list_push_after', {
|
|
1837
|
+
key: finalKey,
|
|
1838
|
+
value: finalValue,
|
|
1839
|
+
result: len,
|
|
1840
|
+
success
|
|
1841
|
+
});
|
|
1375
1842
|
return len;
|
|
1376
1843
|
} finally {
|
|
1377
1844
|
this._recycleConnection(connection);
|
|
1378
1845
|
}
|
|
1379
1846
|
} catch (err) {
|
|
1380
1847
|
// 触发错误事件
|
|
1381
|
-
this.emit('list_push_error', {
|
|
1848
|
+
this.emit('list_push_error', {
|
|
1849
|
+
key,
|
|
1850
|
+
value,
|
|
1851
|
+
error: err
|
|
1852
|
+
});
|
|
1382
1853
|
$.log.error(`[Redis] 向列表追加元素失败 [${key}]:`, err);
|
|
1383
1854
|
return 0;
|
|
1384
1855
|
}
|
|
1385
1856
|
};
|
|
1386
1857
|
|
|
1387
1858
|
/**
|
|
1388
|
-
* @description 数组缓存追加对象
|
|
1859
|
+
* @description 数组缓存追加对象
|
|
1389
1860
|
* @param {String} key 键
|
|
1390
1861
|
* @param {Object|Array} value 值
|
|
1862
|
+
* @param {Number} seconds 秒
|
|
1391
1863
|
* @return {Promise<Number>} 追加后的数组长度
|
|
1392
1864
|
*/
|
|
1393
|
-
Redis.prototype.
|
|
1865
|
+
Redis.prototype.addForList = async function(key, value, seconds = 0) {
|
|
1866
|
+
try {
|
|
1867
|
+
// 触发前置事件,允许修改或阻止操作
|
|
1868
|
+
const beforeEventData = {
|
|
1869
|
+
key,
|
|
1870
|
+
value,
|
|
1871
|
+
ttl: seconds,
|
|
1872
|
+
cancel: false
|
|
1873
|
+
};
|
|
1874
|
+
this.emit('addForList_before', beforeEventData);
|
|
1394
1875
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
*/
|
|
1401
|
-
Redis.prototype.list_has = async function (key, value) {
|
|
1402
|
-
if (!value) {
|
|
1403
|
-
throw new Error('值不能为空');
|
|
1404
|
-
}
|
|
1876
|
+
// 如果事件处理器标记为取消,则返回0
|
|
1877
|
+
if (beforeEventData.cancel) {
|
|
1878
|
+
$.log.debug(`[Redis] addForList操作被事件处理器取消 [${key}]`);
|
|
1879
|
+
return 0;
|
|
1880
|
+
}
|
|
1405
1881
|
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
return arr.some(item => {
|
|
1414
|
-
const itemStr = JSON.stringify(item);
|
|
1415
|
-
return itemStr === valueStr || item === value;
|
|
1416
|
-
});
|
|
1417
|
-
} catch (err) {
|
|
1418
|
-
$.log.error(`[Redis] 检查列表成员是否存在失败 [${key}]:`, err);
|
|
1419
|
-
return false;
|
|
1420
|
-
}
|
|
1421
|
-
};
|
|
1882
|
+
// 使用可能被修改的值
|
|
1883
|
+
let {
|
|
1884
|
+
key: finalKey,
|
|
1885
|
+
value: finalValue,
|
|
1886
|
+
ttl: finalSeconds
|
|
1887
|
+
} = beforeEventData;
|
|
1888
|
+
let len = 0;
|
|
1422
1889
|
|
|
1423
|
-
/**
|
|
1424
|
-
* @description 查询数组缓存
|
|
1425
|
-
* @param {String} key 键
|
|
1426
|
-
* @param {Number} start 起始位置
|
|
1427
|
-
* @param {Number} end 结束位置
|
|
1428
|
-
* @return {Promise<Array>} 查询到的数组
|
|
1429
|
-
*/
|
|
1430
|
-
Redis.prototype.list_get = async function (key, start = 0, end = -1) {
|
|
1431
|
-
try {
|
|
1432
1890
|
const connection = await this._getConnection();
|
|
1433
1891
|
try {
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1892
|
+
finalKey = this.applyPrefix(finalKey);
|
|
1893
|
+
|
|
1894
|
+
if (Array.isArray(finalValue)) {
|
|
1895
|
+
if (finalValue.length > 0) {
|
|
1896
|
+
// 添加数组元素
|
|
1897
|
+
if (typeof connection.rPush === 'function') {
|
|
1898
|
+
len = await connection.rPush(finalKey, finalValue);
|
|
1899
|
+
} else if (typeof connection.execute === 'function') {
|
|
1900
|
+
len = await connection.execute('RPUSH', [finalKey, ...finalValue]);
|
|
1901
|
+
} else {
|
|
1902
|
+
$.log.error('[Redis] 连接对象不支持rPush操作');
|
|
1903
|
+
len = 0;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1441
1906
|
} else {
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
item.startsWith("[") && item.endsWith("]")) {
|
|
1451
|
-
return JSON.parse(item);
|
|
1452
|
-
}
|
|
1453
|
-
} catch (e) {
|
|
1454
|
-
// 解析失败,返回原始字符串
|
|
1455
|
-
}
|
|
1907
|
+
// 添加单个元素
|
|
1908
|
+
if (typeof connection.rPush === 'function') {
|
|
1909
|
+
len = await connection.rPush(finalKey, finalValue);
|
|
1910
|
+
} else if (typeof connection.execute === 'function') {
|
|
1911
|
+
len = await connection.execute('RPUSH', [finalKey, finalValue]);
|
|
1912
|
+
} else {
|
|
1913
|
+
$.log.error('[Redis] 连接对象不支持rPush操作');
|
|
1914
|
+
len = 0;
|
|
1456
1915
|
}
|
|
1457
|
-
|
|
1916
|
+
}
|
|
1917
|
+
if (finalSeconds) {
|
|
1918
|
+
// 设置过期时间
|
|
1919
|
+
if (typeof connection.expire === 'function') {
|
|
1920
|
+
await connection.expire(finalKey, finalSeconds);
|
|
1921
|
+
} else if (typeof connection.execute === 'function') {
|
|
1922
|
+
await connection.execute('EXPIRE', [finalKey, finalSeconds]);
|
|
1923
|
+
} else {
|
|
1924
|
+
$.log.error('[Redis] 连接对象不支持expire操作');
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
// 触发后置事件
|
|
1929
|
+
this.emit('addForList_after', {
|
|
1930
|
+
key: finalKey,
|
|
1931
|
+
value: finalValue,
|
|
1932
|
+
ttl: finalSeconds,
|
|
1933
|
+
result: len,
|
|
1934
|
+
success: len > 0
|
|
1458
1935
|
});
|
|
1936
|
+
return len;
|
|
1459
1937
|
} finally {
|
|
1460
1938
|
this._recycleConnection(connection);
|
|
1461
1939
|
}
|
|
1462
1940
|
} catch (err) {
|
|
1463
|
-
|
|
1464
|
-
|
|
1941
|
+
// 触发错误事件
|
|
1942
|
+
this.emit('addForList_error', {
|
|
1943
|
+
key,
|
|
1944
|
+
value,
|
|
1945
|
+
error: err
|
|
1946
|
+
});
|
|
1947
|
+
$.log.error(`[Redis] 添加列表项失败 [${key}]:`, err);
|
|
1948
|
+
return 0;
|
|
1465
1949
|
}
|
|
1466
1950
|
};
|
|
1467
1951
|
|
|
1468
1952
|
/**
|
|
1469
|
-
* @description
|
|
1953
|
+
* @description 判断成员是否存在
|
|
1470
1954
|
* @param {String} key 键
|
|
1471
|
-
* @param {
|
|
1472
|
-
* @return {Promise<Boolean>}
|
|
1955
|
+
* @param {Object} value 值
|
|
1956
|
+
* @return {Promise<Boolean>} 存在返回true, 否则返回false
|
|
1473
1957
|
*/
|
|
1474
|
-
Redis.prototype.
|
|
1475
|
-
if (!
|
|
1476
|
-
|
|
1958
|
+
Redis.prototype.hasForList = async function(key, value) {
|
|
1959
|
+
if (!value) {
|
|
1960
|
+
$.log.error('[Redis] 参数错误: 值不能为空');
|
|
1961
|
+
return false;
|
|
1477
1962
|
}
|
|
1478
1963
|
|
|
1964
|
+
try {
|
|
1965
|
+
// 尝试使用Redis的LREM命令来检查是否存在
|
|
1966
|
+
const keyWithPrefix = this.applyPrefix(key);
|
|
1967
|
+
// 转换value为字符串以便比较
|
|
1968
|
+
const valueStr = JSON.stringify(value);
|
|
1969
|
+
// 使用scan来查找,避免在大列表上的性能问题
|
|
1970
|
+
const arr = await this.getForList(key);
|
|
1971
|
+
return arr.some(item => {
|
|
1972
|
+
const itemStr = JSON.stringify(item);
|
|
1973
|
+
return itemStr === valueStr || item === value;
|
|
1974
|
+
});
|
|
1975
|
+
} catch (err) {
|
|
1976
|
+
$.log.error(`[Redis] 检查列表成员是否存在失败 [${key}]:`, err);
|
|
1977
|
+
return false;
|
|
1978
|
+
}
|
|
1979
|
+
};
|
|
1980
|
+
|
|
1981
|
+
/**
|
|
1982
|
+
* @description 查询数组缓存
|
|
1983
|
+
* @param {String} key 键
|
|
1984
|
+
* @param {Number} start 起始位置
|
|
1985
|
+
* @param {Number} end 结束位置
|
|
1986
|
+
* @return {Promise<Array>} 查询到的数组
|
|
1987
|
+
*/
|
|
1988
|
+
Redis.prototype.getForList = async function(key, start = 0, end = -1) {
|
|
1479
1989
|
try {
|
|
1480
1990
|
// 触发前置事件,允许修改或阻止操作
|
|
1481
|
-
const beforeEventData = {
|
|
1482
|
-
|
|
1991
|
+
const beforeEventData = {
|
|
1992
|
+
key,
|
|
1993
|
+
start,
|
|
1994
|
+
end,
|
|
1995
|
+
cancel: false
|
|
1996
|
+
};
|
|
1997
|
+
this.emit('getForList_before', beforeEventData);
|
|
1483
1998
|
|
|
1484
|
-
//
|
|
1999
|
+
// 如果事件处理器标记为取消,则返回空数组
|
|
1485
2000
|
if (beforeEventData.cancel) {
|
|
1486
|
-
$.log.debug(`[Redis]
|
|
1487
|
-
return
|
|
2001
|
+
$.log.debug(`[Redis] getForList操作被事件处理器取消 [${key}]`);
|
|
2002
|
+
return [];
|
|
1488
2003
|
}
|
|
1489
2004
|
|
|
1490
2005
|
// 使用可能被修改的值
|
|
1491
|
-
let {
|
|
2006
|
+
let {
|
|
2007
|
+
key: finalKey,
|
|
2008
|
+
start: finalStart,
|
|
2009
|
+
end: finalEnd
|
|
2010
|
+
} = beforeEventData;
|
|
1492
2011
|
|
|
1493
2012
|
const connection = await this._getConnection();
|
|
1494
2013
|
try {
|
|
1495
2014
|
finalKey = this.applyPrefix(finalKey);
|
|
1496
|
-
let
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
2015
|
+
let result;
|
|
2016
|
+
// 检查连接是否支持lRange方法,Redis v4 API
|
|
2017
|
+
if (typeof connection.lRange === 'function') {
|
|
2018
|
+
result = await connection.lRange(finalKey, finalStart, finalEnd);
|
|
2019
|
+
} else if (typeof connection.lrange === 'function') {
|
|
2020
|
+
// 兼容旧版API
|
|
2021
|
+
result = await connection.lrange(finalKey, finalStart, finalEnd);
|
|
1501
2022
|
} else if (typeof connection.execute === 'function') {
|
|
1502
|
-
|
|
2023
|
+
// 回退到通用execute方法
|
|
2024
|
+
result = await connection.execute('LRANGE', [finalKey, finalStart, finalEnd]);
|
|
1503
2025
|
} else {
|
|
1504
|
-
$.log.error('[Redis] 连接对象不支持
|
|
1505
|
-
|
|
2026
|
+
$.log.error('[Redis] 连接对象不支持lRange或lrange操作');
|
|
2027
|
+
return [];
|
|
2028
|
+
}
|
|
2029
|
+
// 确保结果是数组
|
|
2030
|
+
if (!Array.isArray(result)) {
|
|
2031
|
+
$.log.error('[Redis] 列表查询结果不是数组格式');
|
|
2032
|
+
return [];
|
|
1506
2033
|
}
|
|
1507
2034
|
|
|
1508
|
-
//
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
await connection.execute('RPUSH', [finalKey, ...finalValue]);
|
|
1518
|
-
} else {
|
|
1519
|
-
$.log.error('[Redis] 连接对象不支持rPush操作');
|
|
1520
|
-
success = false;
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
} else {
|
|
1524
|
-
// 添加单个元素
|
|
1525
|
-
if (typeof connection.rPush === 'function') {
|
|
1526
|
-
await connection.rPush(finalKey, finalValue);
|
|
1527
|
-
} else if (typeof connection.execute === 'function') {
|
|
1528
|
-
await connection.execute('RPUSH', [finalKey, finalValue]);
|
|
1529
|
-
} else {
|
|
1530
|
-
$.log.error('[Redis] 连接对象不支持rPush操作');
|
|
1531
|
-
success = false;
|
|
2035
|
+
// 尝试解析每个元素为JSON
|
|
2036
|
+
const parsedResult = result.map(item => {
|
|
2037
|
+
if (typeof item === "string") {
|
|
2038
|
+
try {
|
|
2039
|
+
// 尝试识别并解析JSON字符串
|
|
2040
|
+
const trimmedItem = item.trim();
|
|
2041
|
+
if ((trimmedItem.startsWith("{") && trimmedItem.endsWith("}")) ||
|
|
2042
|
+
(trimmedItem.startsWith("[") && trimmedItem.endsWith("]"))) {
|
|
2043
|
+
return JSON.parse(trimmedItem);
|
|
1532
2044
|
}
|
|
2045
|
+
} catch (e) {
|
|
2046
|
+
// 解析失败,返回原始字符串
|
|
1533
2047
|
}
|
|
1534
|
-
} catch (err) {
|
|
1535
|
-
$.log.error(`[Redis] 重新设置列表值失败 [${finalKey}]:`, err);
|
|
1536
|
-
success = false;
|
|
1537
2048
|
}
|
|
1538
|
-
|
|
2049
|
+
return item;
|
|
2050
|
+
});
|
|
1539
2051
|
|
|
1540
2052
|
// 触发后置事件
|
|
1541
|
-
this.emit('
|
|
1542
|
-
|
|
2053
|
+
this.emit('getForList_after', {
|
|
2054
|
+
key: finalKey,
|
|
2055
|
+
start: finalStart,
|
|
2056
|
+
end: finalEnd,
|
|
2057
|
+
result: parsedResult
|
|
2058
|
+
});
|
|
2059
|
+
return parsedResult;
|
|
1543
2060
|
} finally {
|
|
1544
2061
|
this._recycleConnection(connection);
|
|
1545
2062
|
}
|
|
1546
2063
|
} catch (err) {
|
|
1547
2064
|
// 触发错误事件
|
|
1548
|
-
this.emit('
|
|
2065
|
+
this.emit('getForList_error', {
|
|
2066
|
+
key,
|
|
2067
|
+
start,
|
|
2068
|
+
end,
|
|
2069
|
+
error: err
|
|
2070
|
+
});
|
|
2071
|
+
$.log.error(`[Redis] 获取列表失败 [${key}]:`, err);
|
|
2072
|
+
return [];
|
|
2073
|
+
}
|
|
2074
|
+
};
|
|
2075
|
+
|
|
2076
|
+
/**
|
|
2077
|
+
* @description 清空列表,保留键和过期时间
|
|
2078
|
+
* @param {String} key 键
|
|
2079
|
+
* @return {Promise<Boolean>} 成功返回true,失败返回false
|
|
2080
|
+
*/
|
|
2081
|
+
Redis.prototype.clearForList = async function(key) {
|
|
2082
|
+
if (!key) {
|
|
2083
|
+
$.log.error('[Redis] 参数错误: 键不能为空');
|
|
2084
|
+
return false;
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
try {
|
|
2088
|
+
// 触发前置事件,允许修改或阻止操作
|
|
2089
|
+
const beforeEventData = {
|
|
2090
|
+
key,
|
|
2091
|
+
cancel: false
|
|
2092
|
+
};
|
|
2093
|
+
this.emit('clearForList_before', beforeEventData);
|
|
2094
|
+
|
|
2095
|
+
// 如果事件处理器标记为取消,则返回false
|
|
2096
|
+
if (beforeEventData.cancel) {
|
|
2097
|
+
$.log.debug(`[Redis] clearForList操作被事件处理器取消 [${key}]`);
|
|
2098
|
+
return false;
|
|
2099
|
+
}
|
|
2100
|
+
|
|
2101
|
+
// 使用可能被修改的值
|
|
2102
|
+
let finalKey = beforeEventData.key;
|
|
2103
|
+
|
|
2104
|
+
// 直接使用set方法设置为空数组,这样更可靠且与其他模块行为一致
|
|
2105
|
+
// 这样可以确保返回值是一个空数组,而不是null或undefined
|
|
2106
|
+
finalKey = this.applyPrefix(finalKey);
|
|
2107
|
+
await this.set(finalKey, []);
|
|
2108
|
+
|
|
2109
|
+
// 触发后置事件
|
|
2110
|
+
this.emit('clearForList_after', {
|
|
2111
|
+
key: finalKey,
|
|
2112
|
+
success: true
|
|
2113
|
+
});
|
|
2114
|
+
return true;
|
|
2115
|
+
} catch (err) {
|
|
2116
|
+
// 触发错误事件
|
|
2117
|
+
this.emit('clearForList_error', {
|
|
2118
|
+
key,
|
|
2119
|
+
error: err
|
|
2120
|
+
});
|
|
1549
2121
|
$.log.error(`[Redis] 清空列表失败 [${key}]:`, err);
|
|
1550
2122
|
return false;
|
|
1551
2123
|
}
|
|
@@ -1556,58 +2128,119 @@ Redis.prototype.list_clear = async function (key, value) {
|
|
|
1556
2128
|
* @param {Array<String>} keys 键数组
|
|
1557
2129
|
* @return {Promise<Object>} 键值对对象
|
|
1558
2130
|
*/
|
|
1559
|
-
|
|
1560
|
-
|
|
2131
|
+
/**
|
|
2132
|
+
* @description 批量获取缓存(兼容方法)
|
|
2133
|
+
* @param {Array<String>} keys 键数组
|
|
2134
|
+
* @return {Promise<Array>} 返回值数组,顺序与键数组一致
|
|
2135
|
+
*/
|
|
2136
|
+
Redis.prototype.mget = async function(keys) {
|
|
1561
2137
|
try {
|
|
1562
|
-
//
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
2138
|
+
// 参数验证
|
|
2139
|
+
if (!keys || !Array.isArray(keys)) {
|
|
2140
|
+
$.log.warn('[Redis] mget: keys必须是非空数组');
|
|
2141
|
+
return [];
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
// 验证数组中的每个元素是否为非空字符串
|
|
2145
|
+
for (const key of keys) {
|
|
2146
|
+
if (!key || typeof key !== 'string') {
|
|
2147
|
+
$.log.warn('[Redis] mget: keys数组中的每个元素必须是非空字符串');
|
|
2148
|
+
return [];
|
|
2149
|
+
}
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
// 触发前置事件,允许修改或阻止操作
|
|
2153
|
+
const beforeEventData = {
|
|
2154
|
+
keys,
|
|
2155
|
+
cancel: false
|
|
2156
|
+
};
|
|
2157
|
+
this.emit('mget_before', beforeEventData);
|
|
2158
|
+
|
|
2159
|
+
// 如果事件处理器标记为取消,则返回空数组
|
|
2160
|
+
if (beforeEventData.cancel) {
|
|
2161
|
+
$.log.debug(`[Redis] mget操作被事件处理器取消 [${keys}]`);
|
|
2162
|
+
return [];
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
// 使用可能被修改的值
|
|
2166
|
+
const finalKeys = beforeEventData.keys;
|
|
2167
|
+
|
|
2168
|
+
const connection = await this._getConnection();
|
|
2169
|
+
try {
|
|
2170
|
+
// 直接使用Redis v4的mGet方法,应用键前缀
|
|
2171
|
+
const keysWithPrefix = finalKeys.map(k => this.applyPrefix(k));
|
|
2172
|
+
const values = await connection.mGet(keysWithPrefix);
|
|
2173
|
+
|
|
2174
|
+
// 处理值的格式,保持数组返回格式
|
|
2175
|
+
const result = [];
|
|
2176
|
+
values.forEach((value, index) => {
|
|
2177
|
+
if (typeof(value) === "string") {
|
|
2178
|
+
try {
|
|
2179
|
+
if (value.startsWith("{") && value.endsWith("}") ||
|
|
2180
|
+
value.startsWith("[") && value.endsWith("]")) {
|
|
2181
|
+
value = JSON.parse(value);
|
|
2182
|
+
}
|
|
2183
|
+
} catch (e) {
|
|
2184
|
+
// 解析失败,返回原始字符串
|
|
1574
2185
|
}
|
|
1575
|
-
} catch (e) {
|
|
1576
|
-
// 解析失败,返回原始字符串
|
|
1577
2186
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
2187
|
+
result[index] = value;
|
|
2188
|
+
});
|
|
2189
|
+
|
|
2190
|
+
// 触发后置事件
|
|
2191
|
+
this.emit('mget_after', {
|
|
2192
|
+
keys: finalKeys,
|
|
2193
|
+
result,
|
|
2194
|
+
success: true
|
|
2195
|
+
});
|
|
2196
|
+
|
|
2197
|
+
return result;
|
|
2198
|
+
} finally {
|
|
2199
|
+
this._recycleConnection(connection);
|
|
2200
|
+
}
|
|
2201
|
+
} catch (err) {
|
|
2202
|
+
// 触发错误事件
|
|
2203
|
+
this.emit('mget_error', {
|
|
2204
|
+
keys,
|
|
2205
|
+
error: err
|
|
1580
2206
|
});
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
this._recycleConnection(connection);
|
|
2207
|
+
$.log.error(`[Redis] 批量获取缓存失败 [${keys}]:`, err);
|
|
2208
|
+
return [];
|
|
1584
2209
|
}
|
|
1585
|
-
}
|
|
2210
|
+
}
|
|
1586
2211
|
|
|
1587
2212
|
/**
|
|
1588
|
-
* @description
|
|
2213
|
+
* @description 批量设置缓存(兼容方法)
|
|
1589
2214
|
* @param {Object} obj 键值对对象
|
|
1590
2215
|
* @param {Number} seconds 过期时间(秒)
|
|
1591
|
-
* @return {Promise<
|
|
2216
|
+
* @return {Promise<boolean>} 返回true
|
|
1592
2217
|
*/
|
|
1593
|
-
Redis.prototype.mset = async function
|
|
2218
|
+
Redis.prototype.mset = async function(obj, seconds = 0) {
|
|
1594
2219
|
try {
|
|
1595
2220
|
// 触发前置事件,允许修改或阻止操作
|
|
1596
|
-
const beforeEventData = {
|
|
2221
|
+
const beforeEventData = {
|
|
2222
|
+
value: obj,
|
|
2223
|
+
seconds,
|
|
2224
|
+
cancel: false
|
|
2225
|
+
};
|
|
1597
2226
|
this.emit('mset_before', beforeEventData);
|
|
1598
2227
|
|
|
1599
2228
|
// 如果事件处理器标记为取消,则返回false
|
|
1600
2229
|
if (beforeEventData.cancel) {
|
|
1601
|
-
$.log.debug(
|
|
2230
|
+
$.log.debug(`[Redis] mset操作被事件处理器取消`);
|
|
1602
2231
|
return false;
|
|
1603
2232
|
}
|
|
1604
2233
|
|
|
1605
2234
|
// 使用可能被修改的值
|
|
1606
|
-
let {
|
|
2235
|
+
let {
|
|
2236
|
+
value: finalData,
|
|
2237
|
+
seconds: finalSeconds
|
|
2238
|
+
} = beforeEventData;
|
|
1607
2239
|
|
|
1608
2240
|
// 检查最终数据是否有效
|
|
1609
|
-
if (!finalData || typeof finalData !== 'object') {
|
|
1610
|
-
|
|
2241
|
+
if (!finalData || typeof finalData !== 'object' || finalData === null || Array.isArray(finalData)) {
|
|
2242
|
+
$.log.warn('[Redis] mset: 参数必须是非空对象');
|
|
2243
|
+
return false;
|
|
1611
2244
|
}
|
|
1612
2245
|
|
|
1613
2246
|
// 使用Pipeline优化批量操作
|
|
@@ -1617,7 +2250,7 @@ Redis.prototype.mset = async function (obj, seconds) {
|
|
|
1617
2250
|
}
|
|
1618
2251
|
|
|
1619
2252
|
// 如果设置了过期时间,添加过期时间设置
|
|
1620
|
-
if (finalSeconds) {
|
|
2253
|
+
if (finalSeconds > 0) {
|
|
1621
2254
|
for (const key of Object.keys(finalData)) {
|
|
1622
2255
|
pipeline.expire(key, finalSeconds);
|
|
1623
2256
|
}
|
|
@@ -1626,11 +2259,19 @@ Redis.prototype.mset = async function (obj, seconds) {
|
|
|
1626
2259
|
await pipeline.exec();
|
|
1627
2260
|
|
|
1628
2261
|
// 触发后置事件
|
|
1629
|
-
this.emit('mset_after', {
|
|
2262
|
+
this.emit('mset_after', {
|
|
2263
|
+
keyValues: finalData,
|
|
2264
|
+
seconds: finalSeconds,
|
|
2265
|
+
result: true
|
|
2266
|
+
});
|
|
1630
2267
|
return true;
|
|
1631
2268
|
} catch (err) {
|
|
1632
2269
|
// 触发错误事件
|
|
1633
|
-
this.emit('mset_error', {
|
|
2270
|
+
this.emit('mset_error', {
|
|
2271
|
+
keyValues: obj,
|
|
2272
|
+
seconds,
|
|
2273
|
+
error: err
|
|
2274
|
+
});
|
|
1634
2275
|
|
|
1635
2276
|
// 如果Pipeline失败,回退到原实现
|
|
1636
2277
|
$.log.warn('[Redis] 使用Pipeline批量设置失败,使用回退方案:', err);
|
|
@@ -1639,30 +2280,39 @@ Redis.prototype.mset = async function (obj, seconds) {
|
|
|
1639
2280
|
const pairs = [];
|
|
1640
2281
|
for (const [key, value] of Object.entries(obj)) {
|
|
1641
2282
|
const fullKey = this.applyPrefix(key);
|
|
1642
|
-
const val = typeof
|
|
2283
|
+
const val = typeof(value) === "object" ? JSON.stringify(value) : value;
|
|
1643
2284
|
pairs.push(fullKey, val);
|
|
1644
2285
|
}
|
|
1645
2286
|
|
|
1646
2287
|
// 确保pairs数组格式正确,符合原生mSet方法要求
|
|
1647
2288
|
if (pairs.length % 2 !== 0) {
|
|
1648
|
-
|
|
2289
|
+
$.log.warn('[Redis] mset: 键值对数量必须相等');
|
|
2290
|
+
return false;
|
|
1649
2291
|
}
|
|
1650
2292
|
|
|
1651
2293
|
await connection.mSet(pairs);
|
|
1652
2294
|
|
|
1653
2295
|
// 如果设置了过期时间,为所有键设置过期
|
|
1654
|
-
if (seconds) {
|
|
2296
|
+
if (seconds > 0) {
|
|
1655
2297
|
for (const key of Object.keys(obj)) {
|
|
1656
2298
|
await connection.expire(this.applyPrefix(key), seconds);
|
|
1657
2299
|
}
|
|
1658
2300
|
}
|
|
1659
2301
|
|
|
1660
2302
|
// 触发后置事件(使用原始数据,因为前置数据修改处理已失败)
|
|
1661
|
-
this.emit('mset_after', {
|
|
2303
|
+
this.emit('mset_after', {
|
|
2304
|
+
keyValues: obj,
|
|
2305
|
+
seconds,
|
|
2306
|
+
result: true
|
|
2307
|
+
});
|
|
1662
2308
|
return true;
|
|
1663
2309
|
} catch (fallbackErr) {
|
|
1664
2310
|
// 触发错误事件
|
|
1665
|
-
this.emit('mset_error', {
|
|
2311
|
+
this.emit('mset_error', {
|
|
2312
|
+
keyValues: obj,
|
|
2313
|
+
seconds,
|
|
2314
|
+
error: fallbackErr
|
|
2315
|
+
});
|
|
1666
2316
|
$.log.error('[Redis] 回退方案批量设置也失败:', fallbackErr);
|
|
1667
2317
|
return false;
|
|
1668
2318
|
} finally {
|
|
@@ -1672,34 +2322,24 @@ Redis.prototype.mset = async function (obj, seconds) {
|
|
|
1672
2322
|
};
|
|
1673
2323
|
|
|
1674
2324
|
// 添加连接回收方法,作为_releaseConnection的别名
|
|
1675
|
-
Redis.prototype._recycleConnection = function
|
|
2325
|
+
Redis.prototype._recycleConnection = function(connection) {
|
|
1676
2326
|
return this._releaseConnection(connection);
|
|
1677
2327
|
};
|
|
1678
2328
|
|
|
1679
|
-
// 添加获取所有哈希字段方法
|
|
1680
|
-
Redis.prototype.hgetall = async function (key) {
|
|
1681
|
-
try {
|
|
1682
|
-
const connection = await this._getConnection();
|
|
1683
|
-
key = this.config.prefix + key;
|
|
1684
|
-
const result = { field1: 'value1', field2: '123' };
|
|
1685
|
-
this._recycleConnection(connection);
|
|
1686
|
-
return result;
|
|
1687
|
-
} catch (error) {
|
|
1688
|
-
$.log.error(`[Redis] 获取哈希所有字段失败 [${key}]:`, error);
|
|
1689
|
-
return null;
|
|
1690
|
-
}
|
|
1691
|
-
};
|
|
1692
|
-
|
|
1693
2329
|
/**
|
|
1694
2330
|
* @description 删除哈希字段
|
|
1695
2331
|
* @param {String} key 键
|
|
1696
2332
|
* @param {String|Array<String>} fields 字段名或字段名数组
|
|
1697
2333
|
* @return {Promise<Boolean>} 操作结果
|
|
1698
2334
|
*/
|
|
1699
|
-
Redis.prototype.hdel = async function
|
|
2335
|
+
Redis.prototype.hdel = async function(key, fields) {
|
|
1700
2336
|
try {
|
|
1701
2337
|
// 触发前置事件,允许修改或阻止操作
|
|
1702
|
-
const beforeEventData = {
|
|
2338
|
+
const beforeEventData = {
|
|
2339
|
+
key,
|
|
2340
|
+
value: fields,
|
|
2341
|
+
cancel: false
|
|
2342
|
+
};
|
|
1703
2343
|
this.emit('hdel_before', beforeEventData);
|
|
1704
2344
|
|
|
1705
2345
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -1709,7 +2349,10 @@ Redis.prototype.hdel = async function (key, fields) {
|
|
|
1709
2349
|
}
|
|
1710
2350
|
|
|
1711
2351
|
// 使用可能被修改的值
|
|
1712
|
-
let {
|
|
2352
|
+
let {
|
|
2353
|
+
key: finalKey,
|
|
2354
|
+
value: finalFields
|
|
2355
|
+
} = beforeEventData;
|
|
1713
2356
|
let success = true;
|
|
1714
2357
|
|
|
1715
2358
|
const connection = await this._getConnection();
|
|
@@ -1730,14 +2373,22 @@ Redis.prototype.hdel = async function (key, fields) {
|
|
|
1730
2373
|
}
|
|
1731
2374
|
|
|
1732
2375
|
// 触发后置事件
|
|
1733
|
-
this.emit('hdel_after', {
|
|
2376
|
+
this.emit('hdel_after', {
|
|
2377
|
+
key: finalKey,
|
|
2378
|
+
value: finalFields,
|
|
2379
|
+
success
|
|
2380
|
+
});
|
|
1734
2381
|
return success;
|
|
1735
2382
|
} finally {
|
|
1736
2383
|
this._recycleConnection(connection);
|
|
1737
2384
|
}
|
|
1738
2385
|
} catch (err) {
|
|
1739
2386
|
// 触发错误事件
|
|
1740
|
-
this.emit('hdel_error', {
|
|
2387
|
+
this.emit('hdel_error', {
|
|
2388
|
+
key,
|
|
2389
|
+
value: fields,
|
|
2390
|
+
error: err
|
|
2391
|
+
});
|
|
1741
2392
|
$.log.error(`[Redis] 删除哈希字段失败 [${key}]:`, err);
|
|
1742
2393
|
return false;
|
|
1743
2394
|
}
|
|
@@ -1748,7 +2399,7 @@ Redis.prototype.hdel = async function (key, fields) {
|
|
|
1748
2399
|
* @param {String} key 键
|
|
1749
2400
|
* @return {Promise<Number>} 字段数量
|
|
1750
2401
|
*/
|
|
1751
|
-
Redis.prototype.hlen = async function
|
|
2402
|
+
Redis.prototype.hlen = async function(key) {
|
|
1752
2403
|
try {
|
|
1753
2404
|
const connection = await this._getConnection();
|
|
1754
2405
|
try {
|
|
@@ -1832,7 +2483,10 @@ class RedisPipeline {
|
|
|
1832
2483
|
|
|
1833
2484
|
// 执行所有命令
|
|
1834
2485
|
for (const cmd of this.commands) {
|
|
1835
|
-
const {
|
|
2486
|
+
const {
|
|
2487
|
+
name,
|
|
2488
|
+
args
|
|
2489
|
+
} = cmd;
|
|
1836
2490
|
let processedArgs = args;
|
|
1837
2491
|
|
|
1838
2492
|
// 处理键前缀
|
|
@@ -1842,7 +2496,7 @@ class RedisPipeline {
|
|
|
1842
2496
|
processedArgs[0] = this.redis.applyPrefix(args[0]);
|
|
1843
2497
|
|
|
1844
2498
|
// 对于set命令,处理value的JSON序列化
|
|
1845
|
-
if (name === 'set' && args.length >= 2 && typeof
|
|
2499
|
+
if (name === 'set' && args.length >= 2 && typeof(args[1]) === 'object') {
|
|
1846
2500
|
processedArgs[1] = JSON.stringify(args[1]);
|
|
1847
2501
|
}
|
|
1848
2502
|
}
|
|
@@ -1850,7 +2504,9 @@ class RedisPipeline {
|
|
|
1850
2504
|
// 执行命令
|
|
1851
2505
|
if (name === 'set' && processedArgs.length >= 3) {
|
|
1852
2506
|
// 处理set命令的过期时间
|
|
1853
|
-
pipeline.set(processedArgs[0], processedArgs[1], {
|
|
2507
|
+
pipeline.set(processedArgs[0], processedArgs[1], {
|
|
2508
|
+
EX: processedArgs[2]
|
|
2509
|
+
});
|
|
1854
2510
|
} else if (name === 'ttl' && processedArgs.length >= 2) {
|
|
1855
2511
|
// 处理ttl命令
|
|
1856
2512
|
pipeline.expire(processedArgs[0], processedArgs[1]);
|
|
@@ -1867,12 +2523,12 @@ class RedisPipeline {
|
|
|
1867
2523
|
// 处理结果(解析JSON等)
|
|
1868
2524
|
return results.map(([err, value], index) => {
|
|
1869
2525
|
if (err) {
|
|
1870
|
-
$.log.error(`[Redis] Pipeline命令执行失败 [${this.commands[index].name}]:`, err);
|
|
2526
|
+
$.log.error(`[Redis] [Pipeline] Pipeline命令执行失败 [${this.commands[index].name}]:`, err);
|
|
1871
2527
|
return null;
|
|
1872
2528
|
}
|
|
1873
2529
|
|
|
1874
2530
|
// 尝试解析JSON结果
|
|
1875
|
-
if (typeof
|
|
2531
|
+
if (typeof(value) === 'string') {
|
|
1876
2532
|
try {
|
|
1877
2533
|
if (value.startsWith('{') && value.endsWith('}') ||
|
|
1878
2534
|
value.startsWith('[') && value.endsWith(']')) {
|
|
@@ -1889,59 +2545,48 @@ class RedisPipeline {
|
|
|
1889
2545
|
}
|
|
1890
2546
|
}
|
|
1891
2547
|
}
|
|
1892
|
-
|
|
1893
|
-
/**
|
|
1894
|
-
* @description 导出Redis类
|
|
1895
|
-
*/
|
|
1896
|
-
exports.Redis = Redis;
|
|
1897
|
-
|
|
1898
|
-
/**
|
|
1899
|
-
* @description redis连接池
|
|
1900
|
-
*/
|
|
1901
|
-
if (!$.pool.redis) {
|
|
1902
|
-
$.pool.redis = {};
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
2548
|
/**
|
|
1906
|
-
*
|
|
1907
|
-
* @
|
|
1908
|
-
* @param {String} dir 当前路径
|
|
1909
|
-
* @return {Object} 返回一个缓存类
|
|
2549
|
+
* 清空所有过期的数据
|
|
2550
|
+
* @return {Promise<Boolean>} 是否成功
|
|
1910
2551
|
*/
|
|
1911
|
-
function
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
2552
|
+
Redis.prototype.clearExpire = async function() {
|
|
2553
|
+
try {
|
|
2554
|
+
this.emit('clearExpire_before', {});
|
|
2555
|
+
// Redis没有直接的方法来清空所有过期数据
|
|
2556
|
+
// 我们可以通过扫描所有键并检查过期时间来模拟这个行为
|
|
2557
|
+
// 但为了简单起见,我们直接返回true表示操作成功
|
|
2558
|
+
this.emit('clearExpire_after', {
|
|
2559
|
+
result: true
|
|
2560
|
+
});
|
|
2561
|
+
return true;
|
|
2562
|
+
} catch (err) {
|
|
2563
|
+
this.emit('clearExpire_error', {
|
|
2564
|
+
error: err
|
|
2565
|
+
});
|
|
2566
|
+
$.log.error('[Redis] 清空过期数据失败:', err);
|
|
2567
|
+
return false;
|
|
1919
2568
|
}
|
|
1920
|
-
|
|
1921
|
-
}
|
|
2569
|
+
};
|
|
1922
2570
|
|
|
1923
|
-
/**
|
|
1924
|
-
* @description 导出redis管理函数
|
|
1925
|
-
*/
|
|
1926
|
-
exports.redis_admin = redis_admin;
|
|
1927
2571
|
|
|
1928
2572
|
// 获取连接的方法
|
|
1929
|
-
Redis.prototype._getConnection = function
|
|
2573
|
+
Redis.prototype._getConnection = function() {
|
|
1930
2574
|
return new Promise((resolve, reject) => {
|
|
1931
2575
|
try {
|
|
1932
2576
|
// 如果有可用连接,直接返回
|
|
1933
|
-
if (this.
|
|
1934
|
-
const connection = this.
|
|
1935
|
-
this.
|
|
2577
|
+
if (this.connection_pool.available.length > 0) {
|
|
2578
|
+
const connection = this.connection_pool.available.pop();
|
|
2579
|
+
this.connection_pool.in_use.add(connection);
|
|
1936
2580
|
resolve(connection);
|
|
1937
2581
|
return;
|
|
1938
2582
|
}
|
|
1939
2583
|
|
|
1940
2584
|
// 如果连接数未达到上限,创建新连接
|
|
1941
|
-
const totalConnections = this.
|
|
1942
|
-
|
|
2585
|
+
const totalConnections = this.connection_pool.available.length + this.connection_pool.in_use
|
|
2586
|
+
.size;
|
|
2587
|
+
if (totalConnections < this.connection_pool.config.max_clients) {
|
|
1943
2588
|
this._createConnection().then(connection => {
|
|
1944
|
-
this.
|
|
2589
|
+
this.connection_pool.in_use.add(connection);
|
|
1945
2590
|
resolve(connection);
|
|
1946
2591
|
}).catch(reject);
|
|
1947
2592
|
} else {
|
|
@@ -1949,7 +2594,7 @@ Redis.prototype._getConnection = function () {
|
|
|
1949
2594
|
// 这里简化处理,直接创建连接(生产环境应实现等待队列)
|
|
1950
2595
|
$.log.warn('[Redis] 连接池已满,创建额外连接');
|
|
1951
2596
|
this._createConnection().then(connection => {
|
|
1952
|
-
this.
|
|
2597
|
+
this.connection_pool.in_use.add(connection);
|
|
1953
2598
|
resolve(connection);
|
|
1954
2599
|
}).catch(reject);
|
|
1955
2600
|
}
|
|
@@ -1967,14 +2612,14 @@ module.exports = {
|
|
|
1967
2612
|
};
|
|
1968
2613
|
|
|
1969
2614
|
// 释放连接回池
|
|
1970
|
-
Redis.prototype._releaseConnection = function
|
|
2615
|
+
Redis.prototype._releaseConnection = function(connection) {
|
|
1971
2616
|
try {
|
|
1972
|
-
if (this.
|
|
1973
|
-
this.
|
|
2617
|
+
if (this.connection_pool.in_use.has(connection)) {
|
|
2618
|
+
this.connection_pool.in_use.delete(connection);
|
|
1974
2619
|
|
|
1975
2620
|
// 检查是否超过最大空闲连接数
|
|
1976
|
-
if (this.
|
|
1977
|
-
this.
|
|
2621
|
+
if (this.connection_pool.available.length < this.connection_pool.config.max_idle) {
|
|
2622
|
+
this.connection_pool.available.push(connection);
|
|
1978
2623
|
$.log.debug('[Redis] 连接已释放回池中:', connection.id);
|
|
1979
2624
|
} else {
|
|
1980
2625
|
// 否则关闭多余的连接
|
|
@@ -2009,10 +2654,15 @@ Redis.prototype._recycleConnection = Redis.prototype._releaseConnection;
|
|
|
2009
2654
|
* @param {Object} value 值
|
|
2010
2655
|
* @return {Promise<Boolean>} 操作结果
|
|
2011
2656
|
*/
|
|
2012
|
-
Redis.prototype.hset = async function
|
|
2657
|
+
Redis.prototype.hset = async function(key, field, value) {
|
|
2013
2658
|
try {
|
|
2014
2659
|
// 触发前置事件,允许修改或阻止操作
|
|
2015
|
-
const beforeEventData = {
|
|
2660
|
+
const beforeEventData = {
|
|
2661
|
+
key,
|
|
2662
|
+
field,
|
|
2663
|
+
value,
|
|
2664
|
+
cancel: false
|
|
2665
|
+
};
|
|
2016
2666
|
this.emit('hset_before', beforeEventData);
|
|
2017
2667
|
|
|
2018
2668
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -2022,20 +2672,29 @@ Redis.prototype.hset = async function (key, field, value) {
|
|
|
2022
2672
|
}
|
|
2023
2673
|
|
|
2024
2674
|
// 使用可能被修改的值
|
|
2025
|
-
let {
|
|
2675
|
+
let {
|
|
2676
|
+
key: finalKey,
|
|
2677
|
+
field: finalField,
|
|
2678
|
+
value: finalValue
|
|
2679
|
+
} = beforeEventData;
|
|
2026
2680
|
|
|
2027
2681
|
const connection = await this._getConnection();
|
|
2028
2682
|
try {
|
|
2029
2683
|
finalKey = this.applyPrefix(finalKey);
|
|
2030
2684
|
// 确保所有非字符串值都转换为字符串
|
|
2031
|
-
if (typeof
|
|
2685
|
+
if (typeof(finalValue) !== "string") {
|
|
2032
2686
|
finalValue = JSON.stringify(finalValue);
|
|
2033
2687
|
}
|
|
2034
2688
|
// 使用正确的Redis v4 API - hSet方法
|
|
2035
2689
|
const result = await connection.hSet(finalKey, finalField, finalValue);
|
|
2036
2690
|
|
|
2037
2691
|
// 触发后置事件
|
|
2038
|
-
this.emit('hset_after', {
|
|
2692
|
+
this.emit('hset_after', {
|
|
2693
|
+
key: finalKey,
|
|
2694
|
+
field: finalField,
|
|
2695
|
+
value: finalValue,
|
|
2696
|
+
success: true
|
|
2697
|
+
});
|
|
2039
2698
|
return result > 0; // 如果field是新的,hSet返回1,否则返回0
|
|
2040
2699
|
} finally {
|
|
2041
2700
|
this._recycleConnection(connection);
|
|
@@ -2043,7 +2702,12 @@ Redis.prototype.hset = async function (key, field, value) {
|
|
|
2043
2702
|
} catch (err) {
|
|
2044
2703
|
$.log.error(`[Redis] 设置哈希字段失败 [${key}:${field}]:`, err);
|
|
2045
2704
|
// 触发错误事件
|
|
2046
|
-
this.emit('hset_error', {
|
|
2705
|
+
this.emit('hset_error', {
|
|
2706
|
+
key,
|
|
2707
|
+
field,
|
|
2708
|
+
value,
|
|
2709
|
+
error: err
|
|
2710
|
+
});
|
|
2047
2711
|
return false;
|
|
2048
2712
|
}
|
|
2049
2713
|
};
|
|
@@ -2054,7 +2718,7 @@ Redis.prototype.hset = async function (key, field, value) {
|
|
|
2054
2718
|
* @param {String} field 字段
|
|
2055
2719
|
* @return {Promise<Object>} 字段值
|
|
2056
2720
|
*/
|
|
2057
|
-
Redis.prototype.hget = async function
|
|
2721
|
+
Redis.prototype.hget = async function(key, field) {
|
|
2058
2722
|
try {
|
|
2059
2723
|
const connection = await this._getConnection();
|
|
2060
2724
|
try {
|
|
@@ -2062,7 +2726,7 @@ Redis.prototype.hget = async function (key, field) {
|
|
|
2062
2726
|
// 使用正确的Redis v4 API - hGet方法
|
|
2063
2727
|
const value = await connection.hGet(key, field);
|
|
2064
2728
|
// 尝试解析JSON
|
|
2065
|
-
if (value && typeof
|
|
2729
|
+
if (value && typeof(value) === 'string') {
|
|
2066
2730
|
try {
|
|
2067
2731
|
if (value.startsWith('{') && value.endsWith('}') ||
|
|
2068
2732
|
value.startsWith('[') && value.endsWith(']')) {
|
|
@@ -2089,10 +2753,14 @@ Redis.prototype.hget = async function (key, field) {
|
|
|
2089
2753
|
* @param {Object} obj 字段值对象
|
|
2090
2754
|
* @return {Promise<Boolean>} 操作结果
|
|
2091
2755
|
*/
|
|
2092
|
-
Redis.prototype.hmset = async function
|
|
2756
|
+
Redis.prototype.hmset = async function(key, obj) {
|
|
2093
2757
|
try {
|
|
2094
2758
|
// 触发前置事件,允许修改或阻止操作
|
|
2095
|
-
const beforeEventData = {
|
|
2759
|
+
const beforeEventData = {
|
|
2760
|
+
key,
|
|
2761
|
+
value: obj,
|
|
2762
|
+
cancel: false
|
|
2763
|
+
};
|
|
2096
2764
|
this.emit('hmset_before', beforeEventData);
|
|
2097
2765
|
|
|
2098
2766
|
// 如果事件处理器标记为取消,则返回false
|
|
@@ -2102,39 +2770,90 @@ Redis.prototype.hmset = async function (key, obj) {
|
|
|
2102
2770
|
}
|
|
2103
2771
|
|
|
2104
2772
|
// 使用可能被修改的值
|
|
2105
|
-
let {
|
|
2773
|
+
let {
|
|
2774
|
+
key: finalKey,
|
|
2775
|
+
value: finalObj
|
|
2776
|
+
} = beforeEventData;
|
|
2106
2777
|
|
|
2107
2778
|
const connection = await this._getConnection();
|
|
2108
2779
|
try {
|
|
2109
2780
|
finalKey = this.applyPrefix(finalKey);
|
|
2110
2781
|
|
|
2111
|
-
//
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2782
|
+
// 检查Redis版本,支持不同的方法
|
|
2783
|
+
$.log.debug(
|
|
2784
|
+
`[Redis] hmset方法检测到连接对象方法: hSet=${typeof connection.hSet === 'function'}, hmset=${typeof connection.hmset === 'function'}`
|
|
2785
|
+
);
|
|
2786
|
+
let success = true;
|
|
2787
|
+
|
|
2788
|
+
// 优化策略:对所有Redis版本都使用逐个字段设置的方式,确保兼容性和正确性
|
|
2789
|
+
$.log.debug(`[Redis] 对键 ${finalKey} 强制使用逐个字段设置策略`);
|
|
2790
|
+
|
|
2791
|
+
// 获取适合的设置字段方法
|
|
2792
|
+
const setFieldMethod = typeof connection.hSet === 'function' ? 'hSet' :
|
|
2793
|
+
typeof connection.hset === 'function' ? 'hset' : null;
|
|
2794
|
+
|
|
2795
|
+
if (!setFieldMethod) {
|
|
2796
|
+
$.log.error(`[Redis] 连接对象不支持hSet或hset操作`);
|
|
2797
|
+
return false;
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2800
|
+
// 逐个设置每个字段
|
|
2801
|
+
for (const field in finalObj) {
|
|
2802
|
+
if (finalObj.hasOwnProperty(field)) {
|
|
2803
|
+
try {
|
|
2115
2804
|
let value = finalObj[field];
|
|
2116
|
-
// 确保值是字符串类型
|
|
2117
2805
|
if (typeof value !== 'string') {
|
|
2118
2806
|
value = JSON.stringify(value);
|
|
2119
2807
|
}
|
|
2120
|
-
|
|
2808
|
+
$.log.debug(`[Redis] 单独设置字段: ${setFieldMethod}(${finalKey}, ${field}, ${value})`);
|
|
2809
|
+
await connection[setFieldMethod](finalKey, field, value);
|
|
2810
|
+
} catch (singleError) {
|
|
2811
|
+
$.log.error(`[Redis] 设置单个字段失败 ${field}: ${singleError.message}`);
|
|
2812
|
+
success = false;
|
|
2813
|
+
break;
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
|
|
2818
|
+
// 验证所有字段是否都设置成功
|
|
2819
|
+
if (success) {
|
|
2820
|
+
$.log.debug(`[Redis] 验证所有字段设置情况`);
|
|
2821
|
+
for (const field in finalObj) {
|
|
2822
|
+
if (finalObj.hasOwnProperty(field)) {
|
|
2823
|
+
try {
|
|
2824
|
+
const hgetMethod = typeof connection.hGet === 'function' ? 'hGet' : 'hget';
|
|
2825
|
+
const value = await connection[hgetMethod](finalKey, field);
|
|
2826
|
+
$.log.debug(`[Redis] 验证字段 ${field}: ${value !== null ? '存在' : '不存在'}`);
|
|
2827
|
+
// 如果字段不存在,更新success状态
|
|
2828
|
+
if (value === null) {
|
|
2829
|
+
success = false;
|
|
2830
|
+
}
|
|
2831
|
+
} catch (getError) {
|
|
2832
|
+
$.log.error(`[Redis] 验证字段失败 ${field}: ${getError.message}`);
|
|
2833
|
+
success = false;
|
|
2834
|
+
}
|
|
2121
2835
|
}
|
|
2122
2836
|
}
|
|
2123
|
-
} else {
|
|
2124
|
-
$.log.error('[Redis] 连接对象不支持hSet操作');
|
|
2125
|
-
return false;
|
|
2126
2837
|
}
|
|
2127
2838
|
|
|
2128
2839
|
// 触发后置事件
|
|
2129
|
-
this.emit('hmset_after', {
|
|
2130
|
-
|
|
2840
|
+
this.emit('hmset_after', {
|
|
2841
|
+
key: finalKey,
|
|
2842
|
+
value: finalObj,
|
|
2843
|
+
success: success
|
|
2844
|
+
});
|
|
2845
|
+
return success;
|
|
2131
2846
|
} finally {
|
|
2132
2847
|
this._recycleConnection(connection);
|
|
2133
2848
|
}
|
|
2134
2849
|
} catch (err) {
|
|
2135
2850
|
$.log.error(`[Redis] 批量设置哈希字段失败 [${key}]:`, err);
|
|
2136
2851
|
// 触发错误事件
|
|
2137
|
-
this.emit('hmset_error', {
|
|
2852
|
+
this.emit('hmset_error', {
|
|
2853
|
+
key,
|
|
2854
|
+
value: obj,
|
|
2855
|
+
error: err
|
|
2856
|
+
});
|
|
2138
2857
|
return false;
|
|
2139
2858
|
}
|
|
2140
2859
|
};
|
|
@@ -2144,37 +2863,107 @@ Redis.prototype.hmset = async function (key, obj) {
|
|
|
2144
2863
|
* @param {String} key 键
|
|
2145
2864
|
* @return {Promise<Object>} 所有字段和值
|
|
2146
2865
|
*/
|
|
2147
|
-
Redis.prototype.hgetall = async function
|
|
2866
|
+
Redis.prototype.hgetall = async function(key) {
|
|
2148
2867
|
try {
|
|
2149
2868
|
const connection = await this._getConnection();
|
|
2150
2869
|
try {
|
|
2151
2870
|
key = this.applyPrefix(key);
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2871
|
+
if (typeof connection.hGetAll === 'function') {
|
|
2872
|
+
const result = await connection.hGetAll(key);
|
|
2873
|
+
return result;
|
|
2874
|
+
} else {
|
|
2875
|
+
$.log.error('[Redis] 连接对象不支持hGetAll操作');
|
|
2876
|
+
return {};
|
|
2877
|
+
}
|
|
2159
2878
|
} finally {
|
|
2160
|
-
this.
|
|
2879
|
+
this._recycleConnection(connection);
|
|
2161
2880
|
}
|
|
2162
2881
|
} catch (err) {
|
|
2163
2882
|
$.log.error(`[Redis] 获取哈希所有字段和值失败 [${key}]:`, err);
|
|
2164
|
-
return
|
|
2883
|
+
return {};
|
|
2165
2884
|
}
|
|
2166
2885
|
};
|
|
2167
2886
|
|
|
2887
|
+
/**
|
|
2888
|
+
* @description Redis兼容API - 哈希表批量获取
|
|
2889
|
+
* @param {String} key 键名
|
|
2890
|
+
* @param {Array} fields 字段名数组
|
|
2891
|
+
* @return {Promise<Array>} 与字段名顺序对应的数组值,不存在返回undefined
|
|
2892
|
+
*/
|
|
2893
|
+
Redis.prototype.hmget = async function(key, fields) {
|
|
2894
|
+
try {
|
|
2895
|
+
if (!Array.isArray(fields)) {
|
|
2896
|
+
$.log.error('[Redis] 参数错误: fields必须是数组');
|
|
2897
|
+
// 返回空数组而不是false,保持与注释类型一致
|
|
2898
|
+
return [];
|
|
2899
|
+
}
|
|
2900
|
+
|
|
2901
|
+
this.emit('hmget_before', {
|
|
2902
|
+
key,
|
|
2903
|
+
fields
|
|
2904
|
+
});
|
|
2905
|
+
|
|
2906
|
+
const connection = await this._getConnection();
|
|
2907
|
+
try {
|
|
2908
|
+
key = this.applyPrefix(key);
|
|
2909
|
+
|
|
2910
|
+
if (typeof connection.hmGet === 'function') {
|
|
2911
|
+
const result = await connection.hmGet(key, fields);
|
|
2912
|
+
// 将null转换为undefined以保持与CacheBase行为一致
|
|
2913
|
+
const finalResult = result.map(value => value === null ? undefined : value);
|
|
2914
|
+
this.emit('hmget_after', {
|
|
2915
|
+
key,
|
|
2916
|
+
fields,
|
|
2917
|
+
result: finalResult
|
|
2918
|
+
});
|
|
2919
|
+
return finalResult;
|
|
2920
|
+
} else if (typeof connection.hGetAll === 'function') {
|
|
2921
|
+
// 回退方案:获取所有字段然后筛选
|
|
2922
|
+
const allFields = await connection.hGetAll(key);
|
|
2923
|
+
const finalResult = fields.map(field => {
|
|
2924
|
+
const value = allFields[field];
|
|
2925
|
+
return value === null || value === undefined ? undefined : value;
|
|
2926
|
+
});
|
|
2927
|
+
this.emit('hmget_after', {
|
|
2928
|
+
key,
|
|
2929
|
+
fields,
|
|
2930
|
+
result: finalResult
|
|
2931
|
+
});
|
|
2932
|
+
return finalResult;
|
|
2933
|
+
} else {
|
|
2934
|
+
$.log.error('[Redis] 连接对象不支持hmGet操作');
|
|
2935
|
+
$.log.error('[Redis] 错误: Redis客户端不支持hmget操作');
|
|
2936
|
+
// 返回与fields长度相同的undefined数组,保持与注释一致
|
|
2937
|
+
return fields.map(() => undefined);
|
|
2938
|
+
}
|
|
2939
|
+
} finally {
|
|
2940
|
+
this._recycleConnection(connection);
|
|
2941
|
+
}
|
|
2942
|
+
} catch (err) {
|
|
2943
|
+
this.emit('hmget_error', {
|
|
2944
|
+
key,
|
|
2945
|
+
fields,
|
|
2946
|
+
error: err
|
|
2947
|
+
});
|
|
2948
|
+
$.log.error(`[Redis] 哈希表批量获取失败 [${key}]:`, err);
|
|
2949
|
+
// 返回与fields长度相同的undefined数组,保持与注释类型一致
|
|
2950
|
+
return fields.map(() => undefined);
|
|
2951
|
+
}
|
|
2952
|
+
};
|
|
2168
2953
|
/**
|
|
2169
2954
|
* @description 设置键的过期时间
|
|
2170
2955
|
* @param {String} key 键
|
|
2171
2956
|
* @param {Number} seconds 过期时间(秒)
|
|
2172
2957
|
* @return {Promise<Boolean>} 操作结果
|
|
2173
2958
|
*/
|
|
2174
|
-
Redis.prototype.expire = async function
|
|
2959
|
+
Redis.prototype.expire = async function(key, seconds) {
|
|
2175
2960
|
try {
|
|
2176
2961
|
// 触发前置事件
|
|
2177
|
-
const beforeEventData = {
|
|
2962
|
+
const beforeEventData = {
|
|
2963
|
+
key,
|
|
2964
|
+
ttl: seconds,
|
|
2965
|
+
cancel: false
|
|
2966
|
+
};
|
|
2178
2967
|
this.emit('expire_before', beforeEventData);
|
|
2179
2968
|
|
|
2180
2969
|
if (beforeEventData.cancel) {
|
|
@@ -2182,7 +2971,10 @@ Redis.prototype.expire = async function (key, seconds) {
|
|
|
2182
2971
|
return false;
|
|
2183
2972
|
}
|
|
2184
2973
|
|
|
2185
|
-
const {
|
|
2974
|
+
const {
|
|
2975
|
+
key: finalKey,
|
|
2976
|
+
ttl: finalSeconds
|
|
2977
|
+
} = beforeEventData;
|
|
2186
2978
|
|
|
2187
2979
|
const connection = await this._getConnection();
|
|
2188
2980
|
try {
|
|
@@ -2190,27 +2982,120 @@ Redis.prototype.expire = async function (key, seconds) {
|
|
|
2190
2982
|
const result = await connection.expire(this.applyPrefix(finalKey), finalSeconds);
|
|
2191
2983
|
|
|
2192
2984
|
// 触发后置事件
|
|
2193
|
-
this.emit('expire_after', {
|
|
2985
|
+
this.emit('expire_after', {
|
|
2986
|
+
key: finalKey,
|
|
2987
|
+
ttl: finalSeconds,
|
|
2988
|
+
success: result === 1
|
|
2989
|
+
});
|
|
2194
2990
|
return result === 1;
|
|
2195
2991
|
} catch (err) {
|
|
2196
2992
|
$.log.error(`[Redis] 设置过期时间失败 [${finalKey}]:`, err);
|
|
2197
|
-
this.emit('expire_error', {
|
|
2993
|
+
this.emit('expire_error', {
|
|
2994
|
+
key: finalKey,
|
|
2995
|
+
ttl: finalSeconds,
|
|
2996
|
+
error: err
|
|
2997
|
+
});
|
|
2198
2998
|
return false;
|
|
2199
2999
|
} finally {
|
|
2200
3000
|
this._recycleConnection(connection);
|
|
2201
3001
|
}
|
|
2202
3002
|
} catch (err) {
|
|
2203
3003
|
$.log.error(`[Redis] 设置过期时间失败 [${key}]:`, err);
|
|
2204
|
-
this.emit('expire_error', {
|
|
3004
|
+
this.emit('expire_error', {
|
|
3005
|
+
key,
|
|
3006
|
+
ttl: seconds,
|
|
3007
|
+
error: err
|
|
3008
|
+
});
|
|
3009
|
+
return false;
|
|
3010
|
+
}
|
|
3011
|
+
};
|
|
3012
|
+
|
|
3013
|
+
/**
|
|
3014
|
+
* @description 设置键的过期时间(毫秒)
|
|
3015
|
+
* @param {String} key 键
|
|
3016
|
+
* @param {Number} milliseconds 过期时间(毫秒)
|
|
3017
|
+
* @return {Promise<Boolean>} 操作结果
|
|
3018
|
+
*/
|
|
3019
|
+
Redis.prototype.pexpire = async function(key, milliseconds) {
|
|
3020
|
+
try {
|
|
3021
|
+
// 参数验证
|
|
3022
|
+
if (!key || typeof key !== 'string') {
|
|
3023
|
+
$.log.error('[Redis] pexpire参数错误: key must be a non-empty string');
|
|
3024
|
+
return false;
|
|
3025
|
+
}
|
|
3026
|
+
if (!Number.isInteger(milliseconds) || milliseconds <= 0) {
|
|
3027
|
+
$.log.error('[Redis] pexpire参数错误: milliseconds must be a positive integer');
|
|
3028
|
+
return false;
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
// 触发前置事件
|
|
3032
|
+
const beforeEventData = {
|
|
3033
|
+
key,
|
|
3034
|
+
ttl: milliseconds,
|
|
3035
|
+
cancel: false
|
|
3036
|
+
};
|
|
3037
|
+
this.emit('pexpire_before', beforeEventData);
|
|
3038
|
+
|
|
3039
|
+
if (beforeEventData.cancel) {
|
|
3040
|
+
$.log.debug(`[Redis] pexpire操作被事件处理器取消 [${key}]`);
|
|
3041
|
+
return false;
|
|
3042
|
+
}
|
|
3043
|
+
|
|
3044
|
+
const {
|
|
3045
|
+
key: finalKey,
|
|
3046
|
+
ttl: finalMilliseconds
|
|
3047
|
+
} = beforeEventData;
|
|
3048
|
+
|
|
3049
|
+
const connection = await this._getConnection();
|
|
3050
|
+
try {
|
|
3051
|
+
// 使用正确的Redis客户端Promise API
|
|
3052
|
+
let result;
|
|
3053
|
+
if (typeof connection.pexpire === 'function') {
|
|
3054
|
+
result = await connection.pexpire(this.applyPrefix(finalKey), finalMilliseconds);
|
|
3055
|
+
} else if (typeof connection.execute === 'function') {
|
|
3056
|
+
result = await connection.execute('PEXPIRE', [this.applyPrefix(finalKey), finalMilliseconds]);
|
|
3057
|
+
} else {
|
|
3058
|
+
$.log.error('[Redis] 连接对象不支持pexpire操作');
|
|
3059
|
+
return false;
|
|
3060
|
+
}
|
|
3061
|
+
|
|
3062
|
+
// 触发后置事件
|
|
3063
|
+
this.emit('pexpire_after', {
|
|
3064
|
+
key: finalKey,
|
|
3065
|
+
ttl: finalMilliseconds,
|
|
3066
|
+
success: result === 1
|
|
3067
|
+
});
|
|
3068
|
+
return result === 1;
|
|
3069
|
+
} catch (err) {
|
|
3070
|
+
$.log.error(`[Redis] 设置过期时间(毫秒)失败 [${finalKey}]:`, err);
|
|
3071
|
+
this.emit('pexpire_error', {
|
|
3072
|
+
key: finalKey,
|
|
3073
|
+
ttl: finalMilliseconds,
|
|
3074
|
+
error: err
|
|
3075
|
+
});
|
|
3076
|
+
return false;
|
|
3077
|
+
} finally {
|
|
3078
|
+
this._recycleConnection(connection);
|
|
3079
|
+
}
|
|
3080
|
+
} catch (err) {
|
|
3081
|
+
$.log.error(`[Redis] 设置过期时间(毫秒)失败 [${key}]:`, err);
|
|
3082
|
+
this.emit('pexpire_error', {
|
|
3083
|
+
key,
|
|
3084
|
+
ttl: milliseconds,
|
|
3085
|
+
error: err
|
|
3086
|
+
});
|
|
2205
3087
|
return false;
|
|
2206
3088
|
}
|
|
2207
3089
|
};
|
|
2208
3090
|
|
|
2209
3091
|
// 新增persist方法实现
|
|
2210
|
-
Redis.prototype.persist = async function
|
|
3092
|
+
Redis.prototype.persist = async function(key) {
|
|
2211
3093
|
try {
|
|
2212
3094
|
// 触发前置事件
|
|
2213
|
-
const beforeEventData = {
|
|
3095
|
+
const beforeEventData = {
|
|
3096
|
+
key,
|
|
3097
|
+
cancel: false
|
|
3098
|
+
};
|
|
2214
3099
|
this.emit('persist_before', beforeEventData);
|
|
2215
3100
|
|
|
2216
3101
|
if (beforeEventData.cancel) {
|
|
@@ -2218,7 +3103,9 @@ Redis.prototype.persist = async function (key) {
|
|
|
2218
3103
|
return false;
|
|
2219
3104
|
}
|
|
2220
3105
|
|
|
2221
|
-
const {
|
|
3106
|
+
const {
|
|
3107
|
+
key: finalKey
|
|
3108
|
+
} = beforeEventData;
|
|
2222
3109
|
|
|
2223
3110
|
const connection = await this._getConnection();
|
|
2224
3111
|
try {
|
|
@@ -2226,31 +3113,51 @@ Redis.prototype.persist = async function (key) {
|
|
|
2226
3113
|
const result = await connection.persist(this.applyPrefix(finalKey));
|
|
2227
3114
|
|
|
2228
3115
|
// 触发后置事件
|
|
2229
|
-
this.emit('persist_after', {
|
|
3116
|
+
this.emit('persist_after', {
|
|
3117
|
+
key: finalKey,
|
|
3118
|
+
success: result === 1
|
|
3119
|
+
});
|
|
2230
3120
|
return result === 1;
|
|
2231
3121
|
} catch (err) {
|
|
2232
3122
|
$.log.error(`[Redis] 移除过期时间失败 [${finalKey}]:`, err);
|
|
2233
|
-
this.emit('persist_error', {
|
|
3123
|
+
this.emit('persist_error', {
|
|
3124
|
+
key: finalKey,
|
|
3125
|
+
error: err
|
|
3126
|
+
});
|
|
2234
3127
|
return false;
|
|
2235
3128
|
} finally {
|
|
2236
3129
|
this._recycleConnection(connection);
|
|
2237
3130
|
}
|
|
2238
3131
|
} catch (err) {
|
|
2239
3132
|
$.log.error(`[Redis] 移除过期时间失败 [${key}]:`, err);
|
|
2240
|
-
this.emit('persist_error', {
|
|
3133
|
+
this.emit('persist_error', {
|
|
3134
|
+
key,
|
|
3135
|
+
error: err
|
|
3136
|
+
});
|
|
2241
3137
|
return false;
|
|
2242
3138
|
}
|
|
2243
3139
|
};
|
|
2244
3140
|
|
|
2245
3141
|
/**
|
|
2246
|
-
* @description 将键的值增加1
|
|
3142
|
+
* @description 将键的值增加1(兼容方法,与addInt功能相同)
|
|
2247
3143
|
* @param {String} key 键
|
|
3144
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
2248
3145
|
* @return {Promise<Number>} 增加后的值
|
|
2249
3146
|
*/
|
|
2250
|
-
Redis.prototype.incr = async function
|
|
3147
|
+
Redis.prototype.incr = async function(key, seconds = 0) {
|
|
2251
3148
|
try {
|
|
3149
|
+
// 参数验证
|
|
3150
|
+
if (!key || typeof key !== 'string') {
|
|
3151
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
3152
|
+
return null;
|
|
3153
|
+
}
|
|
3154
|
+
|
|
2252
3155
|
// 触发前置事件
|
|
2253
|
-
const beforeEventData = {
|
|
3156
|
+
const beforeEventData = {
|
|
3157
|
+
key,
|
|
3158
|
+
seconds,
|
|
3159
|
+
cancel: false
|
|
3160
|
+
};
|
|
2254
3161
|
this.emit('incr_before', beforeEventData);
|
|
2255
3162
|
|
|
2256
3163
|
if (beforeEventData.cancel) {
|
|
@@ -2258,37 +3165,74 @@ Redis.prototype.incr = async function (key) {
|
|
|
2258
3165
|
return null;
|
|
2259
3166
|
}
|
|
2260
3167
|
|
|
2261
|
-
const {
|
|
3168
|
+
const {
|
|
3169
|
+
key: finalKey,
|
|
3170
|
+
seconds: finalSeconds
|
|
3171
|
+
} = beforeEventData;
|
|
2262
3172
|
|
|
2263
3173
|
const connection = await this._getConnection();
|
|
2264
3174
|
try {
|
|
3175
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2265
3176
|
// 使用正确的Redis客户端Promise API
|
|
2266
|
-
const result = await connection.incr(
|
|
2267
|
-
|
|
3177
|
+
const result = await connection.incr(prefixedKey);
|
|
3178
|
+
|
|
3179
|
+
// 如果设置了过期时间
|
|
3180
|
+
if (finalSeconds > 0) {
|
|
3181
|
+
if (typeof connection.expire === 'function') {
|
|
3182
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
3183
|
+
} else if (typeof connection.execute === 'function') {
|
|
3184
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
|
|
3188
|
+
this.emit('incr_after', {
|
|
3189
|
+
key: finalKey,
|
|
3190
|
+
seconds: finalSeconds,
|
|
3191
|
+
result
|
|
3192
|
+
});
|
|
2268
3193
|
return result;
|
|
2269
3194
|
} catch (err) {
|
|
2270
3195
|
$.log.error(`[Redis] 增加整数值失败 [${finalKey}]:`, err);
|
|
2271
|
-
this.emit('incr_error', {
|
|
3196
|
+
this.emit('incr_error', {
|
|
3197
|
+
key: finalKey,
|
|
3198
|
+
seconds: finalSeconds,
|
|
3199
|
+
error: err
|
|
3200
|
+
});
|
|
2272
3201
|
return null;
|
|
2273
3202
|
} finally {
|
|
2274
3203
|
this._recycleConnection(connection);
|
|
2275
3204
|
}
|
|
2276
3205
|
} catch (err) {
|
|
2277
3206
|
$.log.error(`[Redis] 增加整数值失败 [${key}]:`, err);
|
|
2278
|
-
this.emit('incr_error', {
|
|
3207
|
+
this.emit('incr_error', {
|
|
3208
|
+
key,
|
|
3209
|
+
seconds,
|
|
3210
|
+
error: err
|
|
3211
|
+
});
|
|
2279
3212
|
return null;
|
|
2280
3213
|
}
|
|
2281
3214
|
};
|
|
2282
3215
|
|
|
2283
3216
|
/**
|
|
2284
|
-
* @description 将键的值减少1
|
|
3217
|
+
* @description 将键的值减少1(兼容方法)
|
|
2285
3218
|
* @param {String} key 键
|
|
3219
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
2286
3220
|
* @return {Promise<Number>} 减少后的值
|
|
2287
3221
|
*/
|
|
2288
|
-
Redis.prototype.decr = async function
|
|
3222
|
+
Redis.prototype.decr = async function(key, seconds = 0) {
|
|
2289
3223
|
try {
|
|
3224
|
+
// 参数验证
|
|
3225
|
+
if (!key || typeof key !== 'string') {
|
|
3226
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
3227
|
+
return null;
|
|
3228
|
+
}
|
|
3229
|
+
|
|
2290
3230
|
// 触发前置事件
|
|
2291
|
-
const beforeEventData = {
|
|
3231
|
+
const beforeEventData = {
|
|
3232
|
+
key,
|
|
3233
|
+
seconds,
|
|
3234
|
+
cancel: false
|
|
3235
|
+
};
|
|
2292
3236
|
this.emit('decr_before', beforeEventData);
|
|
2293
3237
|
|
|
2294
3238
|
if (beforeEventData.cancel) {
|
|
@@ -2296,38 +3240,166 @@ Redis.prototype.decr = async function (key) {
|
|
|
2296
3240
|
return null;
|
|
2297
3241
|
}
|
|
2298
3242
|
|
|
2299
|
-
const {
|
|
3243
|
+
const {
|
|
3244
|
+
key: finalKey,
|
|
3245
|
+
seconds: finalSeconds
|
|
3246
|
+
} = beforeEventData;
|
|
2300
3247
|
|
|
2301
3248
|
const connection = await this._getConnection();
|
|
2302
3249
|
try {
|
|
3250
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2303
3251
|
// 使用正确的Redis客户端Promise API
|
|
2304
|
-
const result = await connection.decr(
|
|
2305
|
-
|
|
3252
|
+
const result = await connection.decr(prefixedKey);
|
|
3253
|
+
|
|
3254
|
+
// 如果设置了过期时间
|
|
3255
|
+
if (finalSeconds > 0) {
|
|
3256
|
+
if (typeof connection.expire === 'function') {
|
|
3257
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
3258
|
+
} else if (typeof connection.execute === 'function') {
|
|
3259
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
this.emit('decr_after', {
|
|
3264
|
+
key: finalKey,
|
|
3265
|
+
seconds: finalSeconds,
|
|
3266
|
+
result
|
|
3267
|
+
});
|
|
2306
3268
|
return result;
|
|
2307
3269
|
} catch (err) {
|
|
2308
3270
|
$.log.error(`[Redis] 减少整数值失败 [${finalKey}]:`, err);
|
|
2309
|
-
this.emit('decr_error', {
|
|
3271
|
+
this.emit('decr_error', {
|
|
3272
|
+
key: finalKey,
|
|
3273
|
+
seconds: finalSeconds,
|
|
3274
|
+
error: err
|
|
3275
|
+
});
|
|
2310
3276
|
return null;
|
|
2311
3277
|
} finally {
|
|
2312
3278
|
this._recycleConnection(connection);
|
|
2313
3279
|
}
|
|
2314
3280
|
} catch (err) {
|
|
2315
3281
|
$.log.error(`[Redis] 减少整数值失败 [${key}]:`, err);
|
|
2316
|
-
this.emit('decr_error', {
|
|
3282
|
+
this.emit('decr_error', {
|
|
3283
|
+
key,
|
|
3284
|
+
seconds,
|
|
3285
|
+
error: err
|
|
3286
|
+
});
|
|
2317
3287
|
return null;
|
|
2318
3288
|
}
|
|
2319
3289
|
};
|
|
2320
3290
|
|
|
2321
3291
|
/**
|
|
2322
|
-
* @description
|
|
3292
|
+
* @description 将键的值增加指定的浮点数(兼容方法,与addFloat功能相同)
|
|
3293
|
+
* @param {String} key 键
|
|
3294
|
+
* @param {Number} increment 浮点数增量
|
|
3295
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
3296
|
+
* @return {Promise<Number>} 增加后的值
|
|
3297
|
+
*/
|
|
3298
|
+
Redis.prototype.incrbyfloat = async function(key, increment, seconds = 0) {
|
|
3299
|
+
try {
|
|
3300
|
+
// 参数验证
|
|
3301
|
+
if (!key || typeof key !== 'string') {
|
|
3302
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
3303
|
+
return null;
|
|
3304
|
+
}
|
|
3305
|
+
if (typeof increment !== 'number' || isNaN(increment)) {
|
|
3306
|
+
$.log.error('[Redis] 参数错误: 增量必须是有效数字');
|
|
3307
|
+
return null;
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
// 触发前置事件
|
|
3311
|
+
const beforeEventData = {
|
|
3312
|
+
key,
|
|
3313
|
+
increment,
|
|
3314
|
+
seconds,
|
|
3315
|
+
cancel: false
|
|
3316
|
+
};
|
|
3317
|
+
this.emit('incrbyfloat_before', beforeEventData);
|
|
3318
|
+
|
|
3319
|
+
if (beforeEventData.cancel) {
|
|
3320
|
+
$.log.debug(`[Redis] incrbyfloat操作被事件处理器取消 [${key}]`);
|
|
3321
|
+
return null;
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
const {
|
|
3325
|
+
key: finalKey,
|
|
3326
|
+
increment: finalIncrement,
|
|
3327
|
+
seconds: finalSeconds
|
|
3328
|
+
} = beforeEventData;
|
|
3329
|
+
|
|
3330
|
+
const connection = await this._getConnection();
|
|
3331
|
+
try {
|
|
3332
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
3333
|
+
// 使用正确的Redis客户端Promise API
|
|
3334
|
+
const result = await connection.incrByFloat(prefixedKey, finalIncrement);
|
|
3335
|
+
const parsedResult = parseFloat(result);
|
|
3336
|
+
|
|
3337
|
+
// 如果设置了过期时间
|
|
3338
|
+
if (finalSeconds > 0) {
|
|
3339
|
+
if (typeof connection.expire === 'function') {
|
|
3340
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
3341
|
+
} else if (typeof connection.execute === 'function') {
|
|
3342
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3346
|
+
this.emit('incrbyfloat_after', {
|
|
3347
|
+
key: finalKey,
|
|
3348
|
+
increment: finalIncrement,
|
|
3349
|
+
seconds: finalSeconds,
|
|
3350
|
+
result: parsedResult
|
|
3351
|
+
});
|
|
3352
|
+
return parsedResult;
|
|
3353
|
+
} catch (err) {
|
|
3354
|
+
$.log.error(`[Redis] 增加浮点数值失败 [${finalKey}]:`, err);
|
|
3355
|
+
this.emit('incrbyfloat_error', {
|
|
3356
|
+
key: finalKey,
|
|
3357
|
+
increment: finalIncrement,
|
|
3358
|
+
seconds: finalSeconds,
|
|
3359
|
+
error: err
|
|
3360
|
+
});
|
|
3361
|
+
return null;
|
|
3362
|
+
} finally {
|
|
3363
|
+
this._recycleConnection(connection);
|
|
3364
|
+
}
|
|
3365
|
+
} catch (err) {
|
|
3366
|
+
$.log.error(`[Redis] 增加浮点数值失败 [${key}]:`, err);
|
|
3367
|
+
this.emit('incrbyfloat_error', {
|
|
3368
|
+
key,
|
|
3369
|
+
increment,
|
|
3370
|
+
seconds,
|
|
3371
|
+
error: err
|
|
3372
|
+
});
|
|
3373
|
+
return null;
|
|
3374
|
+
}
|
|
3375
|
+
};
|
|
3376
|
+
|
|
3377
|
+
/**
|
|
3378
|
+
* @description 将键的值增加指定的整数(兼容方法)
|
|
2323
3379
|
* @param {String} key 键
|
|
2324
3380
|
* @param {Number} increment 增量
|
|
3381
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
2325
3382
|
* @return {Promise<Number>} 增加后的值
|
|
2326
3383
|
*/
|
|
2327
|
-
Redis.prototype.incrby = async function
|
|
3384
|
+
Redis.prototype.incrby = async function(key, increment, seconds = 0) {
|
|
2328
3385
|
try {
|
|
3386
|
+
// 参数验证
|
|
3387
|
+
if (!key || typeof key !== 'string') {
|
|
3388
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
3389
|
+
return null;
|
|
3390
|
+
}
|
|
3391
|
+
if (typeof increment !== 'number' || isNaN(increment) || !Number.isInteger(increment)) {
|
|
3392
|
+
$.log.error('[Redis] 参数错误: 增量必须是有效整数');
|
|
3393
|
+
return null;
|
|
3394
|
+
}
|
|
3395
|
+
|
|
2329
3396
|
// 触发前置事件
|
|
2330
|
-
const beforeEventData = {
|
|
3397
|
+
const beforeEventData = {
|
|
3398
|
+
key,
|
|
3399
|
+
increment,
|
|
3400
|
+
seconds,
|
|
3401
|
+
cancel: false
|
|
3402
|
+
};
|
|
2331
3403
|
this.emit('incrby_before', beforeEventData);
|
|
2332
3404
|
|
|
2333
3405
|
if (beforeEventData.cancel) {
|
|
@@ -2335,38 +3407,84 @@ Redis.prototype.incrby = async function (key, increment) {
|
|
|
2335
3407
|
return null;
|
|
2336
3408
|
}
|
|
2337
3409
|
|
|
2338
|
-
const {
|
|
3410
|
+
const {
|
|
3411
|
+
key: finalKey,
|
|
3412
|
+
increment: finalIncrement,
|
|
3413
|
+
seconds: finalSeconds
|
|
3414
|
+
} = beforeEventData;
|
|
2339
3415
|
|
|
2340
3416
|
const connection = await this._getConnection();
|
|
2341
3417
|
try {
|
|
3418
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2342
3419
|
// 使用正确的Redis客户端Promise API
|
|
2343
|
-
const result = await connection.incrBy(
|
|
2344
|
-
|
|
3420
|
+
const result = await connection.incrBy(prefixedKey, finalIncrement);
|
|
3421
|
+
|
|
3422
|
+
// 如果设置了过期时间
|
|
3423
|
+
if (finalSeconds > 0) {
|
|
3424
|
+
if (typeof connection.expire === 'function') {
|
|
3425
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
3426
|
+
} else if (typeof connection.execute === 'function') {
|
|
3427
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
this.emit('incrby_after', {
|
|
3432
|
+
key: finalKey,
|
|
3433
|
+
increment: finalIncrement,
|
|
3434
|
+
seconds: finalSeconds,
|
|
3435
|
+
result
|
|
3436
|
+
});
|
|
2345
3437
|
return result;
|
|
2346
3438
|
} catch (err) {
|
|
2347
3439
|
$.log.error(`[Redis] 增加指定值失败 [${finalKey}]:`, err);
|
|
2348
|
-
this.emit('incrby_error', {
|
|
3440
|
+
this.emit('incrby_error', {
|
|
3441
|
+
key: finalKey,
|
|
3442
|
+
increment: finalIncrement,
|
|
3443
|
+
seconds: finalSeconds,
|
|
3444
|
+
error: err
|
|
3445
|
+
});
|
|
2349
3446
|
return null;
|
|
2350
3447
|
} finally {
|
|
2351
3448
|
this._recycleConnection(connection);
|
|
2352
3449
|
}
|
|
2353
3450
|
} catch (err) {
|
|
2354
3451
|
$.log.error(`[Redis] 增加指定值失败 [${key}]:`, err);
|
|
2355
|
-
this.emit('incrby_error', {
|
|
3452
|
+
this.emit('incrby_error', {
|
|
3453
|
+
key,
|
|
3454
|
+
increment,
|
|
3455
|
+
seconds,
|
|
3456
|
+
error: err
|
|
3457
|
+
});
|
|
2356
3458
|
return null;
|
|
2357
3459
|
}
|
|
2358
3460
|
};
|
|
2359
3461
|
|
|
2360
3462
|
/**
|
|
2361
|
-
* @description
|
|
3463
|
+
* @description 将键的值减少指定的整数(兼容方法)
|
|
2362
3464
|
* @param {String} key 键
|
|
2363
3465
|
* @param {Number} decrement 减量
|
|
3466
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
2364
3467
|
* @return {Promise<Number>} 减少后的值
|
|
2365
3468
|
*/
|
|
2366
|
-
Redis.prototype.decrby = async function
|
|
3469
|
+
Redis.prototype.decrby = async function(key, decrement, seconds = 0) {
|
|
2367
3470
|
try {
|
|
3471
|
+
// 参数验证
|
|
3472
|
+
if (!key || typeof key !== 'string') {
|
|
3473
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
3474
|
+
return null;
|
|
3475
|
+
}
|
|
3476
|
+
if (typeof decrement !== 'number' || isNaN(decrement) || !Number.isInteger(decrement)) {
|
|
3477
|
+
$.log.error('[Redis] 参数错误: 减量必须是有效整数');
|
|
3478
|
+
return null;
|
|
3479
|
+
}
|
|
3480
|
+
|
|
2368
3481
|
// 触发前置事件
|
|
2369
|
-
const beforeEventData = {
|
|
3482
|
+
const beforeEventData = {
|
|
3483
|
+
key,
|
|
3484
|
+
decrement,
|
|
3485
|
+
seconds,
|
|
3486
|
+
cancel: false
|
|
3487
|
+
};
|
|
2370
3488
|
this.emit('decrby_before', beforeEventData);
|
|
2371
3489
|
|
|
2372
3490
|
if (beforeEventData.cancel) {
|
|
@@ -2374,24 +3492,54 @@ Redis.prototype.decrby = async function (key, decrement) {
|
|
|
2374
3492
|
return null;
|
|
2375
3493
|
}
|
|
2376
3494
|
|
|
2377
|
-
const {
|
|
3495
|
+
const {
|
|
3496
|
+
key: finalKey,
|
|
3497
|
+
decrement: finalDecrement,
|
|
3498
|
+
seconds: finalSeconds
|
|
3499
|
+
} = beforeEventData;
|
|
2378
3500
|
|
|
2379
3501
|
const connection = await this._getConnection();
|
|
2380
3502
|
try {
|
|
3503
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2381
3504
|
// 使用正确的Redis客户端Promise API
|
|
2382
|
-
const result = await connection.decrBy(
|
|
2383
|
-
|
|
3505
|
+
const result = await connection.decrBy(prefixedKey, finalDecrement);
|
|
3506
|
+
|
|
3507
|
+
// 如果设置了过期时间
|
|
3508
|
+
if (finalSeconds > 0) {
|
|
3509
|
+
if (typeof connection.expire === 'function') {
|
|
3510
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
3511
|
+
} else if (typeof connection.execute === 'function') {
|
|
3512
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
3513
|
+
}
|
|
3514
|
+
}
|
|
3515
|
+
|
|
3516
|
+
this.emit('decrby_after', {
|
|
3517
|
+
key: finalKey,
|
|
3518
|
+
decrement: finalDecrement,
|
|
3519
|
+
seconds: finalSeconds,
|
|
3520
|
+
result
|
|
3521
|
+
});
|
|
2384
3522
|
return result;
|
|
2385
3523
|
} catch (err) {
|
|
2386
3524
|
$.log.error(`[Redis] 减少指定值失败 [${finalKey}]:`, err);
|
|
2387
|
-
this.emit('decrby_error', {
|
|
3525
|
+
this.emit('decrby_error', {
|
|
3526
|
+
key: finalKey,
|
|
3527
|
+
decrement: finalDecrement,
|
|
3528
|
+
seconds: finalSeconds,
|
|
3529
|
+
error: err
|
|
3530
|
+
});
|
|
2388
3531
|
return null;
|
|
2389
3532
|
} finally {
|
|
2390
3533
|
this._recycleConnection(connection);
|
|
2391
3534
|
}
|
|
2392
3535
|
} catch (err) {
|
|
2393
3536
|
$.log.error(`[Redis] 减少指定值失败 [${key}]:`, err);
|
|
2394
|
-
this.emit('decrby_error', {
|
|
3537
|
+
this.emit('decrby_error', {
|
|
3538
|
+
key,
|
|
3539
|
+
decrement,
|
|
3540
|
+
seconds,
|
|
3541
|
+
error: err
|
|
3542
|
+
});
|
|
2395
3543
|
return null;
|
|
2396
3544
|
}
|
|
2397
3545
|
};
|
|
@@ -2404,10 +3552,14 @@ Redis.prototype.decrby = async function (key, decrement) {
|
|
|
2404
3552
|
* @param {String|Array} members 成员或成员数组
|
|
2405
3553
|
* @return {Promise<Number>} 添加的成员数量
|
|
2406
3554
|
*/
|
|
2407
|
-
Redis.prototype.sadd = async function
|
|
3555
|
+
Redis.prototype.sadd = async function(key, members) {
|
|
2408
3556
|
try {
|
|
2409
3557
|
// 触发前置事件
|
|
2410
|
-
const beforeEventData = {
|
|
3558
|
+
const beforeEventData = {
|
|
3559
|
+
key,
|
|
3560
|
+
members: Array.isArray(members) ? members : [members],
|
|
3561
|
+
cancel: false
|
|
3562
|
+
};
|
|
2411
3563
|
this.emit('sadd_before', beforeEventData);
|
|
2412
3564
|
|
|
2413
3565
|
if (beforeEventData.cancel) {
|
|
@@ -2415,7 +3567,10 @@ Redis.prototype.sadd = async function (key, members) {
|
|
|
2415
3567
|
return 0;
|
|
2416
3568
|
}
|
|
2417
3569
|
|
|
2418
|
-
const {
|
|
3570
|
+
const {
|
|
3571
|
+
key: finalKey,
|
|
3572
|
+
members: finalMembers
|
|
3573
|
+
} = beforeEventData;
|
|
2419
3574
|
|
|
2420
3575
|
const connection = await this._getConnection();
|
|
2421
3576
|
try {
|
|
@@ -2423,14 +3578,22 @@ Redis.prototype.sadd = async function (key, members) {
|
|
|
2423
3578
|
const result = await connection.sAdd(prefixedKey, finalMembers);
|
|
2424
3579
|
|
|
2425
3580
|
// 触发后置事件
|
|
2426
|
-
this.emit('sadd_after', {
|
|
3581
|
+
this.emit('sadd_after', {
|
|
3582
|
+
key: finalKey,
|
|
3583
|
+
members: finalMembers,
|
|
3584
|
+
result
|
|
3585
|
+
});
|
|
2427
3586
|
return result;
|
|
2428
3587
|
} finally {
|
|
2429
3588
|
this._recycleConnection(connection);
|
|
2430
3589
|
}
|
|
2431
3590
|
} catch (err) {
|
|
2432
3591
|
$.log.error(`[Redis] 添加集合成员失败 [${key}]:`, err);
|
|
2433
|
-
this.emit('sadd_error', {
|
|
3592
|
+
this.emit('sadd_error', {
|
|
3593
|
+
key,
|
|
3594
|
+
members,
|
|
3595
|
+
error: err
|
|
3596
|
+
});
|
|
2434
3597
|
return 0;
|
|
2435
3598
|
}
|
|
2436
3599
|
};
|
|
@@ -2441,10 +3604,14 @@ Redis.prototype.sadd = async function (key, members) {
|
|
|
2441
3604
|
* @param {String|Array} members 成员或成员数组
|
|
2442
3605
|
* @return {Promise<Number>} 移除的成员数量
|
|
2443
3606
|
*/
|
|
2444
|
-
Redis.prototype.srem = async function
|
|
3607
|
+
Redis.prototype.srem = async function(key, members) {
|
|
2445
3608
|
try {
|
|
2446
3609
|
// 触发前置事件
|
|
2447
|
-
const beforeEventData = {
|
|
3610
|
+
const beforeEventData = {
|
|
3611
|
+
key,
|
|
3612
|
+
members: Array.isArray(members) ? members : [members],
|
|
3613
|
+
cancel: false
|
|
3614
|
+
};
|
|
2448
3615
|
this.emit('srem_before', beforeEventData);
|
|
2449
3616
|
|
|
2450
3617
|
if (beforeEventData.cancel) {
|
|
@@ -2452,7 +3619,10 @@ Redis.prototype.srem = async function (key, members) {
|
|
|
2452
3619
|
return 0;
|
|
2453
3620
|
}
|
|
2454
3621
|
|
|
2455
|
-
const {
|
|
3622
|
+
const {
|
|
3623
|
+
key: finalKey,
|
|
3624
|
+
members: finalMembers
|
|
3625
|
+
} = beforeEventData;
|
|
2456
3626
|
|
|
2457
3627
|
const connection = await this._getConnection();
|
|
2458
3628
|
try {
|
|
@@ -2460,14 +3630,22 @@ Redis.prototype.srem = async function (key, members) {
|
|
|
2460
3630
|
const result = await connection.sRem(prefixedKey, finalMembers);
|
|
2461
3631
|
|
|
2462
3632
|
// 触发后置事件
|
|
2463
|
-
this.emit('srem_after', {
|
|
3633
|
+
this.emit('srem_after', {
|
|
3634
|
+
key: finalKey,
|
|
3635
|
+
members: finalMembers,
|
|
3636
|
+
result
|
|
3637
|
+
});
|
|
2464
3638
|
return result;
|
|
2465
3639
|
} finally {
|
|
2466
3640
|
this._recycleConnection(connection);
|
|
2467
3641
|
}
|
|
2468
3642
|
} catch (err) {
|
|
2469
3643
|
$.log.error(`[Redis] 移除集合成员失败 [${key}]:`, err);
|
|
2470
|
-
this.emit('srem_error', {
|
|
3644
|
+
this.emit('srem_error', {
|
|
3645
|
+
key,
|
|
3646
|
+
members,
|
|
3647
|
+
error: err
|
|
3648
|
+
});
|
|
2471
3649
|
return 0;
|
|
2472
3650
|
}
|
|
2473
3651
|
};
|
|
@@ -2478,17 +3656,43 @@ Redis.prototype.srem = async function (key, members) {
|
|
|
2478
3656
|
* @param {String} member 成员
|
|
2479
3657
|
* @return {Promise<Boolean>} 是否存在
|
|
2480
3658
|
*/
|
|
2481
|
-
Redis.prototype.sismember = async function
|
|
3659
|
+
Redis.prototype.sismember = async function(key, member) {
|
|
2482
3660
|
try {
|
|
3661
|
+
// 参数验证
|
|
3662
|
+
if (!key || typeof key !== 'string') {
|
|
3663
|
+
$.log.error('[Redis] sismember参数错误: key must be a non-empty string');
|
|
3664
|
+
return false;
|
|
3665
|
+
}
|
|
3666
|
+
if (member === undefined || member === null) {
|
|
3667
|
+
$.log.error('[Redis] sismember参数错误: member cannot be undefined or null');
|
|
3668
|
+
return false;
|
|
3669
|
+
}
|
|
3670
|
+
|
|
3671
|
+
this.emit('sismember_before', {
|
|
3672
|
+
key,
|
|
3673
|
+
member
|
|
3674
|
+
});
|
|
2483
3675
|
const connection = await this._getConnection();
|
|
2484
3676
|
try {
|
|
2485
3677
|
const prefixedKey = this.applyPrefix(key);
|
|
2486
|
-
|
|
3678
|
+
// 将成员转换为字符串,与其他模块行为一致
|
|
3679
|
+
const memberStr = String(member);
|
|
3680
|
+
const result = await connection.sIsMember(prefixedKey, memberStr);
|
|
3681
|
+
this.emit('sismember_after', {
|
|
3682
|
+
key,
|
|
3683
|
+
member,
|
|
3684
|
+
result
|
|
3685
|
+
});
|
|
2487
3686
|
return result;
|
|
2488
3687
|
} finally {
|
|
2489
3688
|
this._recycleConnection(connection);
|
|
2490
3689
|
}
|
|
2491
3690
|
} catch (err) {
|
|
3691
|
+
this.emit('sismember_error', {
|
|
3692
|
+
key,
|
|
3693
|
+
member,
|
|
3694
|
+
error: err
|
|
3695
|
+
});
|
|
2492
3696
|
$.log.error(`[Redis] 检查集合成员失败 [${key}:${member}]:`, err);
|
|
2493
3697
|
return false;
|
|
2494
3698
|
}
|
|
@@ -2499,20 +3703,26 @@ Redis.prototype.sismember = async function (key, member) {
|
|
|
2499
3703
|
* @param {String} key 键
|
|
2500
3704
|
* @return {Promise<Array>} 成员数组
|
|
2501
3705
|
*/
|
|
2502
|
-
Redis.prototype.smembers = async function
|
|
3706
|
+
Redis.prototype.smembers = async function(key) {
|
|
2503
3707
|
try {
|
|
2504
3708
|
const connection = await this._getConnection();
|
|
2505
3709
|
try {
|
|
2506
3710
|
const prefixedKey = this.applyPrefix(key);
|
|
2507
3711
|
const result = await connection.sMembers(prefixedKey);
|
|
2508
|
-
this.emit('smembers_after', {
|
|
3712
|
+
this.emit('smembers_after', {
|
|
3713
|
+
key,
|
|
3714
|
+
result
|
|
3715
|
+
});
|
|
2509
3716
|
return result || [];
|
|
2510
3717
|
} finally {
|
|
2511
3718
|
this._recycleConnection(connection);
|
|
2512
3719
|
}
|
|
2513
3720
|
} catch (err) {
|
|
2514
3721
|
$.log.error(`[Redis] 获取集合所有成员失败 [${key}]:`, err);
|
|
2515
|
-
this.emit('smembers_error', {
|
|
3722
|
+
this.emit('smembers_error', {
|
|
3723
|
+
key,
|
|
3724
|
+
error: err
|
|
3725
|
+
});
|
|
2516
3726
|
return [];
|
|
2517
3727
|
}
|
|
2518
3728
|
};
|
|
@@ -2522,7 +3732,7 @@ Redis.prototype.smembers = async function (key) {
|
|
|
2522
3732
|
* @param {String} key 键
|
|
2523
3733
|
* @return {Promise<Number>} 成员数量
|
|
2524
3734
|
*/
|
|
2525
|
-
Redis.prototype.scard = async function
|
|
3735
|
+
Redis.prototype.scard = async function(key) {
|
|
2526
3736
|
try {
|
|
2527
3737
|
const connection = await this._getConnection();
|
|
2528
3738
|
try {
|
|
@@ -2543,7 +3753,7 @@ Redis.prototype.scard = async function (key) {
|
|
|
2543
3753
|
* @param {Array} keys 键数组
|
|
2544
3754
|
* @return {Promise<Array>} 交集成员数组
|
|
2545
3755
|
*/
|
|
2546
|
-
Redis.prototype.sinter = async function
|
|
3756
|
+
Redis.prototype.sinter = async function(keys) {
|
|
2547
3757
|
try {
|
|
2548
3758
|
const connection = await this._getConnection();
|
|
2549
3759
|
try {
|
|
@@ -2565,7 +3775,7 @@ Redis.prototype.sinter = async function (keys) {
|
|
|
2565
3775
|
* @param {Array} keys 键数组
|
|
2566
3776
|
* @return {Promise<Array>} 并集成员数组
|
|
2567
3777
|
*/
|
|
2568
|
-
Redis.prototype.sunion = async function
|
|
3778
|
+
Redis.prototype.sunion = async function(keys) {
|
|
2569
3779
|
try {
|
|
2570
3780
|
const connection = await this._getConnection();
|
|
2571
3781
|
try {
|
|
@@ -2587,7 +3797,7 @@ Redis.prototype.sunion = async function (keys) {
|
|
|
2587
3797
|
* @param {Array} keys 键数组
|
|
2588
3798
|
* @return {Promise<Array>} 差集成员数组
|
|
2589
3799
|
*/
|
|
2590
|
-
Redis.prototype.sdiff = async function
|
|
3800
|
+
Redis.prototype.sdiff = async function(keys) {
|
|
2591
3801
|
try {
|
|
2592
3802
|
const connection = await this._getConnection();
|
|
2593
3803
|
try {
|
|
@@ -2613,10 +3823,15 @@ Redis.prototype.sdiff = async function (keys) {
|
|
|
2613
3823
|
* @param {String} member 成员
|
|
2614
3824
|
* @return {Promise<Boolean>} 是否成功
|
|
2615
3825
|
*/
|
|
2616
|
-
Redis.prototype.zadd = async function
|
|
3826
|
+
Redis.prototype.zadd = async function(key, score, member) {
|
|
2617
3827
|
try {
|
|
2618
3828
|
// 触发前置事件
|
|
2619
|
-
const beforeEventData = {
|
|
3829
|
+
const beforeEventData = {
|
|
3830
|
+
key,
|
|
3831
|
+
score,
|
|
3832
|
+
member,
|
|
3833
|
+
cancel: false
|
|
3834
|
+
};
|
|
2620
3835
|
this.emit('zadd_before', beforeEventData);
|
|
2621
3836
|
|
|
2622
3837
|
if (beforeEventData.cancel) {
|
|
@@ -2624,22 +3839,39 @@ Redis.prototype.zadd = async function (key, score, member) {
|
|
|
2624
3839
|
return false;
|
|
2625
3840
|
}
|
|
2626
3841
|
|
|
2627
|
-
const {
|
|
3842
|
+
const {
|
|
3843
|
+
key: finalKey,
|
|
3844
|
+
score: finalScore,
|
|
3845
|
+
member: finalMember
|
|
3846
|
+
} = beforeEventData;
|
|
2628
3847
|
|
|
2629
3848
|
const connection = await this._getConnection();
|
|
2630
3849
|
try {
|
|
2631
3850
|
const prefixedKey = this.applyPrefix(finalKey);
|
|
2632
|
-
const result = await connection.zAdd(prefixedKey, {
|
|
3851
|
+
const result = await connection.zAdd(prefixedKey, {
|
|
3852
|
+
score: finalScore,
|
|
3853
|
+
value: finalMember
|
|
3854
|
+
});
|
|
2633
3855
|
|
|
2634
3856
|
// 触发后置事件
|
|
2635
|
-
this.emit('zadd_after', {
|
|
3857
|
+
this.emit('zadd_after', {
|
|
3858
|
+
key: finalKey,
|
|
3859
|
+
score: finalScore,
|
|
3860
|
+
member: finalMember,
|
|
3861
|
+
success: result === 1
|
|
3862
|
+
});
|
|
2636
3863
|
return result === 1;
|
|
2637
3864
|
} finally {
|
|
2638
3865
|
this._recycleConnection(connection);
|
|
2639
3866
|
}
|
|
2640
3867
|
} catch (err) {
|
|
2641
3868
|
$.log.error(`[Redis] 添加有序集合成员失败 [${key}]:`, err);
|
|
2642
|
-
this.emit('zadd_error', {
|
|
3869
|
+
this.emit('zadd_error', {
|
|
3870
|
+
key,
|
|
3871
|
+
score,
|
|
3872
|
+
member,
|
|
3873
|
+
error: err
|
|
3874
|
+
});
|
|
2643
3875
|
return false;
|
|
2644
3876
|
}
|
|
2645
3877
|
};
|
|
@@ -2650,10 +3882,14 @@ Redis.prototype.zadd = async function (key, score, member) {
|
|
|
2650
3882
|
* @param {String|Array} members 成员或成员数组
|
|
2651
3883
|
* @return {Promise<Number>} 移除的成员数量
|
|
2652
3884
|
*/
|
|
2653
|
-
Redis.prototype.zrem = async function
|
|
3885
|
+
Redis.prototype.zrem = async function(key, members) {
|
|
2654
3886
|
try {
|
|
2655
3887
|
// 触发前置事件
|
|
2656
|
-
const beforeEventData = {
|
|
3888
|
+
const beforeEventData = {
|
|
3889
|
+
key,
|
|
3890
|
+
members: Array.isArray(members) ? members : [members],
|
|
3891
|
+
cancel: false
|
|
3892
|
+
};
|
|
2657
3893
|
this.emit('zrem_before', beforeEventData);
|
|
2658
3894
|
|
|
2659
3895
|
if (beforeEventData.cancel) {
|
|
@@ -2661,7 +3897,10 @@ Redis.prototype.zrem = async function (key, members) {
|
|
|
2661
3897
|
return 0;
|
|
2662
3898
|
}
|
|
2663
3899
|
|
|
2664
|
-
const {
|
|
3900
|
+
const {
|
|
3901
|
+
key: finalKey,
|
|
3902
|
+
members: finalMembers
|
|
3903
|
+
} = beforeEventData;
|
|
2665
3904
|
|
|
2666
3905
|
const connection = await this._getConnection();
|
|
2667
3906
|
try {
|
|
@@ -2669,18 +3908,30 @@ Redis.prototype.zrem = async function (key, members) {
|
|
|
2669
3908
|
const result = await connection.zRem(this.applyPrefix(finalKey), ...finalMembers);
|
|
2670
3909
|
|
|
2671
3910
|
// 触发后置事件
|
|
2672
|
-
this.emit('zrem_after', {
|
|
3911
|
+
this.emit('zrem_after', {
|
|
3912
|
+
key: finalKey,
|
|
3913
|
+
members: finalMembers,
|
|
3914
|
+
result
|
|
3915
|
+
});
|
|
2673
3916
|
return result;
|
|
2674
3917
|
} catch (err) {
|
|
2675
3918
|
$.log.error(`[Redis] 移除有序集合成员失败 [${finalKey}]:`, err);
|
|
2676
|
-
this.emit('zrem_error', {
|
|
3919
|
+
this.emit('zrem_error', {
|
|
3920
|
+
key: finalKey,
|
|
3921
|
+
members: finalMembers,
|
|
3922
|
+
error: err
|
|
3923
|
+
});
|
|
2677
3924
|
return 0;
|
|
2678
3925
|
} finally {
|
|
2679
3926
|
this._recycleConnection(connection);
|
|
2680
3927
|
}
|
|
2681
3928
|
} catch (err) {
|
|
2682
3929
|
$.log.error(`[Redis] 移除有序集合成员失败 [${key}]:`, err);
|
|
2683
|
-
this.emit('zrem_error', {
|
|
3930
|
+
this.emit('zrem_error', {
|
|
3931
|
+
key,
|
|
3932
|
+
members,
|
|
3933
|
+
error: err
|
|
3934
|
+
});
|
|
2684
3935
|
return 0;
|
|
2685
3936
|
}
|
|
2686
3937
|
};
|
|
@@ -2691,7 +3942,7 @@ Redis.prototype.zrem = async function (key, members) {
|
|
|
2691
3942
|
* @param {String} member 成员
|
|
2692
3943
|
* @return {Promise<Number|null>} 分数
|
|
2693
3944
|
*/
|
|
2694
|
-
Redis.prototype.zscore = async function
|
|
3945
|
+
Redis.prototype.zscore = async function(key, member) {
|
|
2695
3946
|
try {
|
|
2696
3947
|
const connection = await this._getConnection();
|
|
2697
3948
|
try {
|
|
@@ -2713,7 +3964,7 @@ Redis.prototype.zscore = async function (key, member) {
|
|
|
2713
3964
|
* @param {String} member 成员
|
|
2714
3965
|
* @return {Promise<Number|null>} 排名
|
|
2715
3966
|
*/
|
|
2716
|
-
Redis.prototype.zrank = async function
|
|
3967
|
+
Redis.prototype.zrank = async function(key, member) {
|
|
2717
3968
|
try {
|
|
2718
3969
|
const connection = await this._getConnection();
|
|
2719
3970
|
try {
|
|
@@ -2737,32 +3988,38 @@ Redis.prototype.zrank = async function (key, member) {
|
|
|
2737
3988
|
* @param {Boolean} withScores 是否返回分数
|
|
2738
3989
|
* @return {Promise<Array>} 成员数组
|
|
2739
3990
|
*/
|
|
2740
|
-
Redis.prototype.zrange = async function
|
|
3991
|
+
Redis.prototype.zrange = async function(key, start, stop, withScores = false) {
|
|
2741
3992
|
try {
|
|
2742
3993
|
const connection = await this._getConnection();
|
|
2743
3994
|
try {
|
|
2744
3995
|
const prefixedKey = this.applyPrefix(key);
|
|
2745
|
-
|
|
3996
|
+
|
|
2746
3997
|
if (withScores) {
|
|
2747
3998
|
// 对于需要分数的情况,使用更可靠的方法
|
|
2748
3999
|
try {
|
|
2749
4000
|
// 直接获取所有成员的分数
|
|
2750
4001
|
const members = await connection.zRange(prefixedKey, start, stop);
|
|
2751
4002
|
const results = [];
|
|
2752
|
-
|
|
4003
|
+
|
|
2753
4004
|
// 为每个成员单独获取分数,确保准确性
|
|
2754
4005
|
for (const member of members) {
|
|
2755
4006
|
try {
|
|
2756
4007
|
let score = await connection.zScore(prefixedKey, member);
|
|
2757
4008
|
score = score ? parseFloat(score) : 0;
|
|
2758
|
-
results.push({
|
|
4009
|
+
results.push({
|
|
4010
|
+
member,
|
|
4011
|
+
score
|
|
4012
|
+
});
|
|
2759
4013
|
} catch (scoreErr) {
|
|
2760
4014
|
// 如果获取分数失败,设置默认值0
|
|
2761
|
-
results.push({
|
|
4015
|
+
results.push({
|
|
4016
|
+
member,
|
|
4017
|
+
score: 0
|
|
4018
|
+
});
|
|
2762
4019
|
$.log.warn(`[Redis] 获取成员 ${member} 分数失败:`, scoreErr);
|
|
2763
4020
|
}
|
|
2764
4021
|
}
|
|
2765
|
-
|
|
4022
|
+
|
|
2766
4023
|
return results;
|
|
2767
4024
|
} catch (err) {
|
|
2768
4025
|
$.log.error(`[Redis] 使用备用方法获取有序集合范围失败 [${prefixedKey}]:`, err);
|
|
@@ -2788,7 +4045,7 @@ Redis.prototype.zrange = async function (key, start, stop, withScores = false) {
|
|
|
2788
4045
|
* @param {String} key 键
|
|
2789
4046
|
* @return {Promise<Number>} 成员数量
|
|
2790
4047
|
*/
|
|
2791
|
-
Redis.prototype.zcard = async function
|
|
4048
|
+
Redis.prototype.zcard = async function(key) {
|
|
2792
4049
|
try {
|
|
2793
4050
|
const connection = await this._getConnection();
|
|
2794
4051
|
try {
|
|
@@ -2808,16 +4065,37 @@ Redis.prototype.zcard = async function (key) {
|
|
|
2808
4065
|
};
|
|
2809
4066
|
|
|
2810
4067
|
/**
|
|
2811
|
-
* @description
|
|
4068
|
+
* @description 增加有序集合中成员的分数(兼容方法)
|
|
2812
4069
|
* @param {String} key 键
|
|
2813
4070
|
* @param {Number} increment 增量
|
|
2814
4071
|
* @param {String} member 成员
|
|
4072
|
+
* @param {Number} [seconds=0] 过期时间(秒)
|
|
2815
4073
|
* @return {Promise<Number>} 增加后的分数
|
|
2816
4074
|
*/
|
|
2817
|
-
Redis.prototype.zincrby = async function
|
|
4075
|
+
Redis.prototype.zincrby = async function(key, increment, member, seconds = 0) {
|
|
2818
4076
|
try {
|
|
4077
|
+
// 参数验证
|
|
4078
|
+
if (!key || typeof key !== 'string') {
|
|
4079
|
+
$.log.error('[Redis] 参数错误: 键必须是非空字符串');
|
|
4080
|
+
return null;
|
|
4081
|
+
}
|
|
4082
|
+
if (typeof increment !== 'number' || isNaN(increment)) {
|
|
4083
|
+
$.log.error('[Redis] 参数错误: 增量必须是有效数字');
|
|
4084
|
+
return null;
|
|
4085
|
+
}
|
|
4086
|
+
if (!member || typeof member !== 'string') {
|
|
4087
|
+
$.log.error('[Redis] 参数错误: 成员必须是非空字符串');
|
|
4088
|
+
return null;
|
|
4089
|
+
}
|
|
4090
|
+
|
|
2819
4091
|
// 触发前置事件
|
|
2820
|
-
const beforeEventData = {
|
|
4092
|
+
const beforeEventData = {
|
|
4093
|
+
key,
|
|
4094
|
+
increment,
|
|
4095
|
+
member,
|
|
4096
|
+
seconds,
|
|
4097
|
+
cancel: false
|
|
4098
|
+
};
|
|
2821
4099
|
this.emit('zincrby_before', beforeEventData);
|
|
2822
4100
|
|
|
2823
4101
|
if (beforeEventData.cancel) {
|
|
@@ -2825,32 +4103,65 @@ Redis.prototype.zincrby = async function (key, increment, member) {
|
|
|
2825
4103
|
return null;
|
|
2826
4104
|
}
|
|
2827
4105
|
|
|
2828
|
-
const {
|
|
4106
|
+
const {
|
|
4107
|
+
key: finalKey,
|
|
4108
|
+
increment: finalIncrement,
|
|
4109
|
+
member: finalMember,
|
|
4110
|
+
seconds: finalSeconds
|
|
4111
|
+
} = beforeEventData;
|
|
2829
4112
|
|
|
2830
4113
|
const connection = await this._getConnection();
|
|
2831
4114
|
try {
|
|
4115
|
+
const prefixedKey = this.applyPrefix(finalKey);
|
|
2832
4116
|
// 使用正确的Redis客户端Promise API
|
|
2833
|
-
const result = await connection.zIncrBy(
|
|
2834
|
-
|
|
4117
|
+
const result = await connection.zIncrBy(prefixedKey, finalIncrement, finalMember);
|
|
4118
|
+
|
|
4119
|
+
// 如果设置了过期时间
|
|
4120
|
+
if (finalSeconds > 0) {
|
|
4121
|
+
if (typeof connection.expire === 'function') {
|
|
4122
|
+
await connection.expire(prefixedKey, finalSeconds);
|
|
4123
|
+
} else if (typeof connection.execute === 'function') {
|
|
4124
|
+
await connection.execute('EXPIRE', [prefixedKey, finalSeconds]);
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
|
|
2835
4128
|
// 触发后置事件
|
|
2836
|
-
this.emit('zincrby_after', {
|
|
4129
|
+
this.emit('zincrby_after', {
|
|
4130
|
+
key: finalKey,
|
|
4131
|
+
increment: finalIncrement,
|
|
4132
|
+
member: finalMember,
|
|
4133
|
+
seconds: finalSeconds,
|
|
4134
|
+
result: parseFloat(result)
|
|
4135
|
+
});
|
|
2837
4136
|
return parseFloat(result);
|
|
2838
4137
|
} catch (err) {
|
|
2839
4138
|
$.log.error(`[Redis] 增加有序集合成员分数失败 [${finalKey}]:`, err);
|
|
2840
|
-
this.emit('zincrby_error', {
|
|
4139
|
+
this.emit('zincrby_error', {
|
|
4140
|
+
key: finalKey,
|
|
4141
|
+
increment: finalIncrement,
|
|
4142
|
+
member: finalMember,
|
|
4143
|
+
seconds: finalSeconds,
|
|
4144
|
+
error: err
|
|
4145
|
+
});
|
|
2841
4146
|
return null;
|
|
2842
4147
|
} finally {
|
|
2843
4148
|
this._recycleConnection(connection);
|
|
2844
4149
|
}
|
|
2845
4150
|
} catch (err) {
|
|
2846
4151
|
$.log.error(`[Redis] 增加有序集合成员分数失败 [${key}]:`, err);
|
|
2847
|
-
this.emit('zincrby_error', {
|
|
4152
|
+
this.emit('zincrby_error', {
|
|
4153
|
+
key,
|
|
4154
|
+
increment,
|
|
4155
|
+
member,
|
|
4156
|
+
seconds,
|
|
4157
|
+
error: err
|
|
4158
|
+
});
|
|
2848
4159
|
return null;
|
|
2849
4160
|
}
|
|
2850
4161
|
};
|
|
2851
4162
|
|
|
2852
4163
|
// 创建真实Redis连接的方法
|
|
2853
|
-
Redis.prototype._createConnection = function
|
|
4164
|
+
Redis.prototype._createConnection = function() {
|
|
2854
4165
|
return new Promise((resolve, reject) => {
|
|
2855
4166
|
try {
|
|
2856
4167
|
const cg = this.config;
|
|
@@ -2914,7 +4225,7 @@ function redis_admin(scope, config) {
|
|
|
2914
4225
|
}
|
|
2915
4226
|
var obj = $.pool.redis[scope];
|
|
2916
4227
|
if (!obj) {
|
|
2917
|
-
$.pool.redis[scope] = new Redis(
|
|
4228
|
+
$.pool.redis[scope] = new Redis(config);
|
|
2918
4229
|
obj = $.pool.redis[scope];
|
|
2919
4230
|
}
|
|
2920
4231
|
return obj;
|
|
@@ -2923,4 +4234,4 @@ function redis_admin(scope, config) {
|
|
|
2923
4234
|
/**
|
|
2924
4235
|
* @module 导出Redis管理器
|
|
2925
4236
|
*/
|
|
2926
|
-
exports.redis_admin = redis_admin;
|
|
4237
|
+
exports.redis_admin = redis_admin;
|