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/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 eventEmitter = require('events');
7
- require('mm_logs');
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 eventEmitter {
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(scope, config) {
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.connectionPool = {
46
+ this.connection_pool = {
49
47
  available: [], // 可用连接数组
50
- inUse: new Set(), // 使用中的连接集合
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.retryCount = 0;
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 (key) {
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 (key) {
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 (channel, func) {
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 (channel) {
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 (channel, message) {
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
- throw err;
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 (channel, message) {
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 (channel, message) {
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} cg 配置对象或配置路径
168
+ * @param {Object} config 配置对象或配置路径
170
169
  */
171
170
  // 修复setConfig方法,移除其中的_initPool定义
172
- Redis.prototype.setConfig = function (cg) {
171
+ Redis.prototype.setConfig = function(config) {
173
172
  let obj = {};
174
- if (typeof cg === 'string') {
175
- obj = cg.loadJson(__dirname);
176
- } else if (cg) {
177
- // 合并配置参数
178
- Object.assign(this.config, cg);
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.connectionPool = {
202
+ this.connection_pool = {
205
203
  available: [],
206
- inUse: new Set(),
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.retryCount = 0;
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.retryCount = 0;
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.retryCount >= this.config.retry_count) {
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.retryCount++;
302
- $.log.debug(`[Redis] 尝试第 ${this.retryCount} 次重连...`);
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.connectionPool && this.connectionPool.inUse) {
324
- for (const connection of this.connectionPool.inUse) {
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.connectionPool.inUse.clear();
329
+ this.connection_pool.in_use.clear();
332
330
  }
333
331
 
334
332
  // 关闭所有可用连接
335
- if (this.connectionPool && this.connectionPool.available) {
336
- for (const connection of this.connectionPool.available) {
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.connectionPool.available = [];
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 (key, value, seconds) {
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 (key) {
374
+ get: function(key) {
377
375
  commands.push(['get', key]);
378
376
  return this;
379
377
  },
380
378
 
381
379
  // 删除
382
- del: function (key) {
380
+ del: function(key) {
383
381
  commands.push(['del', key]);
384
382
  return this;
385
383
  },
386
384
 
387
385
  // 判断存在
388
- has: function (key) {
386
+ has: function(key) {
389
387
  commands.push(['has', key]);
390
388
  return this;
391
389
  },
392
390
 
393
391
  // 设置哈希字段
394
- hset: function (key, field, value) {
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 (key, seconds) {
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
- Redis.prototype.ttl = async function (key) {
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
- // 只获取过期时间,符合ttl的标准功能
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] 获取过期时间失败 [${key}]:`, err);
534
- return -2; // -2表示出错
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 (key, num) {
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 = { key, value: num, cancel: false };
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 { key: finalKey, value: finalNum } = beforeEventData;
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
- finalKey = this.applyPrefix(finalKey);
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(finalKey, finalNum);
610
+ result = await connection.incrBy(prefixedKey, finalNum);
567
611
  } else if (typeof connection.execute === 'function') {
568
- result = await connection.execute('INCRBY', [finalKey, finalNum]);
612
+ result = await connection.execute('INCRBY', [prefixedKey, finalNum]);
569
613
  } else {
570
614
  // 如果出错,回退到先获取再设置的方式
571
615
  $.log.warn(`[Redis] 使用原子操作增加整数值失败,使用回退方案`);
572
- let value = await this.get(finalKey);
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(finalKey, n);
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(finalKey, -finalNum);
628
+ result = await connection.decrBy(prefixedKey, -finalNum);
585
629
  } else if (typeof connection.execute === 'function') {
586
- result = await connection.execute('DECRBY', [finalKey, -finalNum]);
630
+ result = await connection.execute('DECRBY', [prefixedKey, -finalNum]);
587
631
  } else {
588
632
  // 如果出错,回退到先获取再设置的方式
589
633
  $.log.warn(`[Redis] 使用原子操作减少整数值失败,使用回退方案`);
590
- let value = await this.get(finalKey);
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(finalKey, n);
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', { key: finalKey, value: finalNum, result, success: true });
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', { key, value: num, error: err });
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 (key, num) {
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 = { key, value: num, cancel: false };
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 { key: finalKey, value: finalNum } = beforeEventData;
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
- finalKey = this.applyPrefix(finalKey);
727
+ const prefixedKey = this.applyPrefix(finalKey);
641
728
 
642
729
  // 优先使用原生方法
643
730
  if (typeof connection.incrByFloat === 'function') {
644
- result = parseFloat(await connection.incrByFloat(finalKey, finalNum));
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', [finalKey, finalNum]));
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(finalKey);
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(finalKey, n);
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', { key: finalKey, value: finalNum, result, success: true });
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(finalKey);
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(finalKey, n);
777
+ await this.set(prefixedKey, n, finalSeconds);
676
778
 
677
779
  // 触发后置事件
678
- this.emit('addFloat_after', { key: finalKey, value: finalNum, result: n, success: true });
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', { key, value: num, error: err });
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 (key, str) {
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 = { key, value: str, cancel: false };
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 { key: finalKey, value: finalStr } = beforeEventData;
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
- finalKey = this.applyPrefix(finalKey);
852
+ const prefixedKey = this.applyPrefix(finalKey);
717
853
 
718
854
  // 优先使用原生方法
719
855
  if (typeof connection.append === 'function') {
720
- result = await connection.append(finalKey, finalStr);
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', [finalKey, finalStr]);
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(finalKey) || '';
865
+ let value = await this.get(prefixedKey) || '';
730
866
  value += finalStr;
731
- await this.set(finalKey, value);
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', { key: finalKey, value: finalStr, result, success: true });
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(finalKey) || '';
892
+ let value = await this.get(prefixedKey) || '';
742
893
  value += finalStr;
743
- await this.set(finalKey, value);
894
+ await this.set(prefixedKey, value, finalSeconds);
744
895
 
745
896
  // 触发后置事件
746
- this.emit('addStr_after', { key: finalKey, value: finalStr, result: value.length, success: true });
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', { key, value: str, error: err });
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 (key) {
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 = { key, cancel: false };
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 { key: finalKey } = beforeEventData;
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', { key: finalKey, success, deleted });
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', { key: finalKey, success, deleted: success ? [finalKey] : [] });
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', { key, error: err });
812
- $.log.error('[Redis] 删除缓存失败:', err);
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
- Redis.prototype.set = async function (key, value, seconds) {
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 = { key, value, ttl: seconds, cancel: false };
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 { key: finalKey, value: finalValue, ttl: finalSeconds } = beforeEventData;
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
- finalKey = this.applyPrefix(finalKey);
842
- if (typeof (finalValue) === "object") {
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(finalKey, finalValue, {
1072
+ if (finalSeconds > 0) {
1073
+ await connection.set(prefixedKey, finalValue, {
848
1074
  EX: finalSeconds
849
1075
  });
850
1076
  } else {
851
- await connection.set(finalKey, finalValue);
1077
+ await connection.set(prefixedKey, finalValue);
852
1078
  }
853
1079
 
854
1080
  // 触发后置事件
855
- this.emit('set_after', { key, value, ttl: seconds, success: true });
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', { key, value, error: err });
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 (key, value, seconds) {
1111
+ Redis.prototype.add = async function(key, value, seconds) {
876
1112
  try {
877
1113
  // 触发前置事件,允许修改或阻止操作
878
- const beforeEventData = { key, value, ttl: seconds, cancel: false };
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 { key: finalKey, value: finalValue, ttl: finalSeconds } = beforeEventData;
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 (finalValue) === "object") {
1138
+ if (typeof(finalValue) === "object") {
894
1139
  finalValue = JSON.stringify(finalValue);
895
1140
  }
896
1141
 
897
- const options = finalSeconds ? { NX: true, EX: finalSeconds } : { NX: true };
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', { key: finalKey, value: finalValue, ttl: finalSeconds, success });
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', { key, value, ttl: seconds, error: err });
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
- Redis.prototype.get = async function (key) {
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
- key = this.applyPrefix(key);
925
- const value = await connection.get(key);
926
- if (typeof (value) === "string") {
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
- return JSON.parse(value);
1220
+ result = JSON.parse(value);
932
1221
  }
933
1222
  } catch (e) {
934
1223
  // 解析失败,返回原始字符串
935
1224
  }
936
1225
  }
937
- return value;
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 (key) {
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
- key = this.applyPrefix(key);
957
- const result = await connection.exists(key);
958
- return result > 0;
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 (key) {
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
- key = this.applyPrefix(key);
978
- const result = await connection.exists(key);
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 (key, start, end) {
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 (str, index, str_sub) {
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 (key, index, value) {
1436
+ Redis.prototype.setrange = async function(key, index, value) {
1038
1437
  try {
1039
1438
  // 触发前置事件,允许修改或阻止操作
1040
- const beforeEventData = { key, index, value, cancel: false };
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 { key: finalKey, index: finalIndex, value: finalValue } = beforeEventData;
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', { key: finalKey, index: finalIndex, value: finalValue, result, success: true });
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', { key: finalKey, index: finalIndex, value: finalValue, result: str.length, success: true });
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', { key, index, value, error: err });
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 (key) {
1536
+ Redis.prototype.clear = async function(key) {
1112
1537
  try {
1113
1538
  // 触发前置事件,允许修改或阻止操作
1114
- const beforeEventData = { key, cancel: false };
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 { key: finalKey } = beforeEventData;
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', { key: finalKey, success });
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', { key, error: err });
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 (key, options = {}) {
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.list_get(key);
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 (pattern = '*') {
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.list_set = async function (key, value, seconds) {
1684
+ Redis.prototype.setForList = async function(key, value, seconds) {
1249
1685
  try {
1250
1686
  // 触发前置事件,允许修改或阻止操作
1251
- const beforeEventData = { key, value, ttl: seconds, cancel: false };
1252
- this.emit('list_set_before', beforeEventData);
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] list_set操作被事件处理器取消 [${key}]`);
1697
+ $.log.debug(`[Redis] setForList操作被事件处理器取消 [${key}]`);
1257
1698
  return 0;
1258
1699
  }
1259
1700
 
1260
1701
  // 使用可能被修改的值
1261
- let { key: finalKey, value: finalValue, ttl: finalSeconds } = beforeEventData;
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('list_set_after', { key: finalKey, value: finalValue, ttl: finalSeconds, result: len, success: len > 0 });
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('list_set_error', { key, value, error: err });
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 (key, value) {
1783
+ Redis.prototype.list_push = async function(key, value) {
1329
1784
  try {
1330
1785
  // 触发前置事件,允许修改或阻止操作
1331
- const beforeEventData = { key, value, cancel: false };
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 { key: finalKey, value: finalValue } = beforeEventData;
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', { key: finalKey, value: finalValue, result: len, success });
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', { key, value, error: err });
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 数组缓存追加对象 (list_push的别名,兼容API)
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.list_add = Redis.prototype.list_push;
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
- * @description 判断成员是否存在
1397
- * @param {String} key 键
1398
- * @param {Object} value 值
1399
- * @return {Promise<Boolean>} 存在返回true, 否则返回false
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
- try {
1407
- // 尝试使用Redis的LREM命令来检查是否存在
1408
- const keyWithPrefix = this.applyPrefix(key);
1409
- // 转换value为字符串以便比较
1410
- const valueStr = JSON.stringify(value);
1411
- // 使用scan来查找,避免在大列表上的性能问题
1412
- const arr = await this.list_get(key);
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
- key = this.applyPrefix(key);
1435
- let result;
1436
- // 检查连接是否支持lRange方法,不支持则使用通用execute方法
1437
- if (typeof connection.lRange === 'function') {
1438
- result = await connection.lRange(key, start, end);
1439
- } else if (typeof connection.execute === 'function') {
1440
- result = await connection.execute('LRANGE', [key, start, end]);
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
- $.log.error('[Redis] 连接对象不支持lRange操作');
1443
- return [];
1444
- }
1445
- // 尝试解析每个元素为JSON
1446
- return result.map(item => {
1447
- if (typeof (item) === "string") {
1448
- try {
1449
- if (item.startsWith("{") && item.endsWith("}") ||
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
- return item;
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
- $.log.error(`[Redis] 获取列表失败 [${key}]:`, err);
1464
- return [];
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 {Array} value 新成员, 没有则删除数组
1472
- * @return {Promise<Boolean>} 成功返回true,失败返回false
1955
+ * @param {Object} value 值
1956
+ * @return {Promise<Boolean>} 存在返回true, 否则返回false
1473
1957
  */
1474
- Redis.prototype.list_clear = async function (key, value) {
1475
- if (!key) {
1476
- throw new Error('键不能为空');
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 = { key, value, cancel: false };
1482
- this.emit('list_clear_before', beforeEventData);
1991
+ const beforeEventData = {
1992
+ key,
1993
+ start,
1994
+ end,
1995
+ cancel: false
1996
+ };
1997
+ this.emit('getForList_before', beforeEventData);
1483
1998
 
1484
- // 如果事件处理器标记为取消,则返回false
1999
+ // 如果事件处理器标记为取消,则返回空数组
1485
2000
  if (beforeEventData.cancel) {
1486
- $.log.debug(`[Redis] list_clear操作被事件处理器取消 [${key}]`);
1487
- return false;
2001
+ $.log.debug(`[Redis] getForList操作被事件处理器取消 [${key}]`);
2002
+ return [];
1488
2003
  }
1489
2004
 
1490
2005
  // 使用可能被修改的值
1491
- let { key: finalKey, value: finalValue } = beforeEventData;
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 success = true;
1497
-
1498
- // 执行删除操作
1499
- if (typeof connection.del === 'function') {
1500
- await connection.del(finalKey);
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
- await connection.execute('DEL', [finalKey]);
2023
+ // 回退到通用execute方法
2024
+ result = await connection.execute('LRANGE', [finalKey, finalStart, finalEnd]);
1503
2025
  } else {
1504
- $.log.error('[Redis] 连接对象不支持del操作');
1505
- success = false;
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
- if (finalValue && success) {
1510
- try {
1511
- if (Array.isArray(finalValue)) {
1512
- if (finalValue.length > 0) {
1513
- // 添加数组元素
1514
- if (typeof connection.rPush === 'function') {
1515
- await connection.rPush(finalKey, finalValue);
1516
- } else if (typeof connection.execute === 'function') {
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('list_clear_after', { key: finalKey, value: finalValue, success });
1542
- return success;
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('list_clear_error', { key, value, error: err });
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
- Redis.prototype.mget = async function (keys) {
1560
- const connection = await this._getConnection();
2131
+ /**
2132
+ * @description 批量获取缓存(兼容方法)
2133
+ * @param {Array<String>} keys 键数组
2134
+ * @return {Promise<Array>} 返回值数组,顺序与键数组一致
2135
+ */
2136
+ Redis.prototype.mget = async function(keys) {
1561
2137
  try {
1562
- // 直接使用Redis v4的mGet方法,应用键前缀
1563
- const keysWithPrefix = keys.map(k => this.applyPrefix(k));
1564
- const values = await connection.mGet(keysWithPrefix);
1565
-
1566
- // 处理值的格式,保持数组返回格式
1567
- const result = [];
1568
- values.forEach((value, index) => {
1569
- if (typeof (value) === "string") {
1570
- try {
1571
- if (value.startsWith("{") && value.endsWith("}") ||
1572
- value.startsWith("[") && value.endsWith("]")) {
1573
- value = JSON.parse(value);
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
- result[index] = value;
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
- return result;
1582
- } finally {
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<Boolean>} 操作结果
2216
+ * @return {Promise<boolean>} 返回true
1592
2217
  */
1593
- Redis.prototype.mset = async function (obj, seconds) {
2218
+ Redis.prototype.mset = async function(obj, seconds = 0) {
1594
2219
  try {
1595
2220
  // 触发前置事件,允许修改或阻止操作
1596
- const beforeEventData = { value: obj, ttl: seconds, cancel: false };
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('[Redis] mset操作被事件处理器取消');
2230
+ $.log.debug(`[Redis] mset操作被事件处理器取消`);
1602
2231
  return false;
1603
2232
  }
1604
2233
 
1605
2234
  // 使用可能被修改的值
1606
- let { value: finalData, ttl: finalSeconds } = beforeEventData;
2235
+ let {
2236
+ value: finalData,
2237
+ seconds: finalSeconds
2238
+ } = beforeEventData;
1607
2239
 
1608
2240
  // 检查最终数据是否有效
1609
- if (!finalData || typeof finalData !== 'object') {
1610
- throw new Error('事件处理后的value必须是非空对象');
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', { value: finalData, ttl: finalSeconds, success: true });
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', { value: obj, ttl: seconds, error: err });
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 (value) === "object" ? JSON.stringify(value) : value;
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
- throw new Error('mset参数格式错误:键值对数量必须相等');
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', { value: obj, ttl: seconds, success: true });
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', { value: obj, ttl: seconds, error: fallbackErr });
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 (connection) {
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 (key, fields) {
2335
+ Redis.prototype.hdel = async function(key, fields) {
1700
2336
  try {
1701
2337
  // 触发前置事件,允许修改或阻止操作
1702
- const beforeEventData = { key, value: fields, cancel: false };
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 { key: finalKey, value: finalFields } = beforeEventData;
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', { key: finalKey, value: finalFields, success });
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', { key, value: fields, error: err });
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 (key) {
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 { name, args } = cmd;
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 (args[1]) === 'object') {
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], { EX: processedArgs[2] });
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 (value) === 'string') {
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
- * @description 缓存管理器,用于创建缓存
1907
- * @param {String} scope 作用域
1908
- * @param {String} dir 当前路径
1909
- * @return {Object} 返回一个缓存类
2549
+ * 清空所有过期的数据
2550
+ * @return {Promise<Boolean>} 是否成功
1910
2551
  */
1911
- function redis_admin(scope, dir) {
1912
- if (!scope) {
1913
- scope = $.val.scope
1914
- }
1915
- var obj = $.pool.redis[scope];
1916
- if (!obj) {
1917
- $.pool.redis[scope] = new Redis(scope, dir);
1918
- obj = $.pool.redis[scope];
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
- return obj;
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.connectionPool.available.length > 0) {
1934
- const connection = this.connectionPool.available.pop();
1935
- this.connectionPool.inUse.add(connection);
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.connectionPool.available.length + this.connectionPool.inUse.size;
1942
- if (totalConnections < this.connectionPool.config.max_clients) {
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.connectionPool.inUse.add(connection);
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.connectionPool.inUse.add(connection);
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 (connection) {
2615
+ Redis.prototype._releaseConnection = function(connection) {
1971
2616
  try {
1972
- if (this.connectionPool.inUse.has(connection)) {
1973
- this.connectionPool.inUse.delete(connection);
2617
+ if (this.connection_pool.in_use.has(connection)) {
2618
+ this.connection_pool.in_use.delete(connection);
1974
2619
 
1975
2620
  // 检查是否超过最大空闲连接数
1976
- if (this.connectionPool.available.length < this.connectionPool.config.max_idle) {
1977
- this.connectionPool.available.push(connection);
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 (key, field, value) {
2657
+ Redis.prototype.hset = async function(key, field, value) {
2013
2658
  try {
2014
2659
  // 触发前置事件,允许修改或阻止操作
2015
- const beforeEventData = { key, field, value, cancel: false };
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 { key: finalKey, field: finalField, value: finalValue } = beforeEventData;
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 (finalValue) !== "string") {
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', { key: finalKey, field: finalField, value: finalValue, success: true });
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', { key, field, value, error: err });
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 (key, field) {
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 (value) === 'string') {
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 (key, obj) {
2756
+ Redis.prototype.hmset = async function(key, obj) {
2093
2757
  try {
2094
2758
  // 触发前置事件,允许修改或阻止操作
2095
- const beforeEventData = { key, value: obj, cancel: false };
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 { key: finalKey, value: finalObj } = beforeEventData;
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
- if (typeof connection.hSet === 'function') {
2113
- for (const field in finalObj) {
2114
- if (finalObj.hasOwnProperty(field)) {
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
- await connection.hSet(finalKey, field, value);
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', { key: finalKey, value: finalObj, success: true });
2130
- return true;
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', { key, value: obj, error: err });
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 (key) {
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
- if (typeof connection.hGetAll === 'function') {
2153
- const result = await connection.hGetAll(key);
2154
- return result;
2155
- } else {
2156
- $.log.error('[Redis] 连接对象不支持hGetAll操作');
2157
- return {};
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._releaseConnection(connection);
2879
+ this._recycleConnection(connection);
2161
2880
  }
2162
2881
  } catch (err) {
2163
2882
  $.log.error(`[Redis] 获取哈希所有字段和值失败 [${key}]:`, err);
2164
- return null;
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 (key, seconds) {
2959
+ Redis.prototype.expire = async function(key, seconds) {
2175
2960
  try {
2176
2961
  // 触发前置事件
2177
- const beforeEventData = { key, ttl: seconds, cancel: false };
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 { key: finalKey, ttl: finalSeconds } = beforeEventData;
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', { key: finalKey, ttl: finalSeconds, success: result === 1 });
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', { key: finalKey, ttl: finalSeconds, error: err });
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', { key, ttl: seconds, error: err });
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 (key) {
3092
+ Redis.prototype.persist = async function(key) {
2211
3093
  try {
2212
3094
  // 触发前置事件
2213
- const beforeEventData = { key, cancel: false };
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 { key: finalKey } = beforeEventData;
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', { key: finalKey, success: result === 1 });
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', { key: finalKey, error: err });
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', { key, error: err });
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 (key) {
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 = { key, cancel: false };
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 { key: finalKey } = beforeEventData;
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(this.applyPrefix(finalKey));
2267
- this.emit('incr_after', { key: finalKey, result });
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', { key: finalKey, error: err });
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', { key, error: err });
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 (key) {
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 = { key, cancel: false };
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 { key: finalKey } = beforeEventData;
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(this.applyPrefix(finalKey));
2305
- this.emit('decr_after', { key: finalKey, result });
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', { key: finalKey, error: err });
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', { key, error: err });
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 (key, increment) {
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 = { key, increment, cancel: false };
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 { key: finalKey, increment: finalIncrement } = beforeEventData;
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(this.applyPrefix(finalKey), finalIncrement);
2344
- this.emit('incrby_after', { key: finalKey, increment: finalIncrement, result });
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', { key: finalKey, increment: finalIncrement, error: err });
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', { key, increment, error: err });
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 (key, decrement) {
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 = { key, decrement, cancel: false };
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 { key: finalKey, decrement: finalDecrement } = beforeEventData;
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(this.applyPrefix(finalKey), finalDecrement);
2383
- this.emit('decrby_after', { key: finalKey, decrement: finalDecrement, result });
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', { key: finalKey, decrement: finalDecrement, error: err });
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', { key, decrement, error: err });
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 (key, members) {
3555
+ Redis.prototype.sadd = async function(key, members) {
2408
3556
  try {
2409
3557
  // 触发前置事件
2410
- const beforeEventData = { key, members: Array.isArray(members) ? members : [members], cancel: false };
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 { key: finalKey, members: finalMembers } = beforeEventData;
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', { key: finalKey, members: finalMembers, result });
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', { key, members, error: err });
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 (key, members) {
3607
+ Redis.prototype.srem = async function(key, members) {
2445
3608
  try {
2446
3609
  // 触发前置事件
2447
- const beforeEventData = { key, members: Array.isArray(members) ? members : [members], cancel: false };
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 { key: finalKey, members: finalMembers } = beforeEventData;
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', { key: finalKey, members: finalMembers, result });
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', { key, members, error: err });
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 (key, member) {
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
- const result = await connection.sIsMember(prefixedKey, member);
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 (key) {
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', { key, result });
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', { key, error: err });
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 (key) {
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 (keys) {
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 (keys) {
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 (keys) {
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 (key, score, member) {
3826
+ Redis.prototype.zadd = async function(key, score, member) {
2617
3827
  try {
2618
3828
  // 触发前置事件
2619
- const beforeEventData = { key, score, member, cancel: false };
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 { key: finalKey, score: finalScore, member: finalMember } = beforeEventData;
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, { score: finalScore, value: finalMember });
3851
+ const result = await connection.zAdd(prefixedKey, {
3852
+ score: finalScore,
3853
+ value: finalMember
3854
+ });
2633
3855
 
2634
3856
  // 触发后置事件
2635
- this.emit('zadd_after', { key: finalKey, score: finalScore, member: finalMember, success: result === 1 });
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', { key, score, member, error: err });
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 (key, members) {
3885
+ Redis.prototype.zrem = async function(key, members) {
2654
3886
  try {
2655
3887
  // 触发前置事件
2656
- const beforeEventData = { key, members: Array.isArray(members) ? members : [members], cancel: false };
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 { key: finalKey, members: finalMembers } = beforeEventData;
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', { key: finalKey, members: finalMembers, result });
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', { key: finalKey, members: finalMembers, error: err });
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', { key, members, error: err });
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 (key, member) {
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 (key, member) {
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 (key, start, stop, withScores = false) {
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({ member, score });
4009
+ results.push({
4010
+ member,
4011
+ score
4012
+ });
2759
4013
  } catch (scoreErr) {
2760
4014
  // 如果获取分数失败,设置默认值0
2761
- results.push({ member, score: 0 });
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 (key) {
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 (key, increment, member) {
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 = { key, increment, member, cancel: false };
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 { key: finalKey, increment: finalIncrement, member: finalMember } = beforeEventData;
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(this.applyPrefix(finalKey), finalIncrement, finalMember);
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', { key: finalKey, increment: finalIncrement, member: finalMember, result: parseFloat(result) });
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', { key: finalKey, increment: finalIncrement, member: finalMember, error: err });
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', { key, increment, member, error: err });
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(scope, config);
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;