befly 3.74.2 → 3.75.0

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.
Files changed (65) hide show
  1. package/apis/dashboard/systemResources.js +3 -1
  2. package/apis/dict/_dict.js +1 -1
  3. package/apis/role/_role.js +2 -2
  4. package/apis/tongJi/dailyStats.js +2 -2
  5. package/apis/tongJi/dailyStatsDistribution.js +3 -3
  6. package/apis/tongJi/errorList.js +2 -2
  7. package/apis/tongJi/errorStats.js +6 -6
  8. package/checks/api.js +11 -6
  9. package/checks/items.js +56 -0
  10. package/checks/menu.js +1 -1
  11. package/checks/table.js +4 -5
  12. package/configs/beflyConfig.json +5 -10
  13. package/configs/constConfig.js +44 -3
  14. package/hooks/auth.js +3 -2
  15. package/hooks/parser.js +15 -4
  16. package/hooks/permission.js +3 -2
  17. package/hooks/rateLimit.js +16 -3
  18. package/hooks/validator.js +2 -1
  19. package/index.js +53 -24
  20. package/lib/cacheHelper.js +83 -229
  21. package/lib/connect.js +3 -13
  22. package/lib/dbHelper.js +57 -142
  23. package/lib/dbParse.js +65 -248
  24. package/lib/dbUtil.js +19 -63
  25. package/lib/logger.js +45 -22
  26. package/lib/redisHelper.js +186 -420
  27. package/lib/smtpText.js +7 -18
  28. package/lib/sqlBuilder.js +22 -51
  29. package/lib/xmlParse.js +15 -59
  30. package/package.json +1 -1
  31. package/plugins/cache.js +2 -3
  32. package/plugins/config.js +3 -1
  33. package/plugins/cron.js +2 -2
  34. package/plugins/email.js +3 -1
  35. package/plugins/logger.js +2 -2
  36. package/plugins/mysql.js +5 -10
  37. package/plugins/redis.js +4 -11
  38. package/plugins/tool.js +3 -3
  39. package/plugins/xmlParse.js +3 -1
  40. package/router/api.js +2 -6
  41. package/router/static.js +9 -10
  42. package/schemas/config.js +4 -4
  43. package/scripts/syncDb/context.js +4 -7
  44. package/scripts/syncDb/diff.js +2 -1
  45. package/scripts/syncDb/index.js +2 -6
  46. package/sync/api.js +7 -8
  47. package/sync/cache.js +3 -1
  48. package/sync/dev.js +28 -65
  49. package/sync/menu.js +5 -6
  50. package/sync/syncUtil.js +25 -0
  51. package/utils/calcPerfTime.js +2 -3
  52. package/utils/crypto.js +0 -40
  53. package/utils/deepMerge.js +2 -6
  54. package/utils/error.js +64 -0
  55. package/utils/fieldClear.js +13 -56
  56. package/utils/importDefault.js +11 -12
  57. package/utils/is.js +5 -182
  58. package/utils/loggerUtils.js +3 -1
  59. package/utils/response.js +12 -8
  60. package/utils/scanFiles.js +2 -53
  61. package/utils/scanSources.js +9 -0
  62. package/utils/util.js +25 -222
  63. package/checks/hook.js +0 -39
  64. package/checks/plugin.js +0 -39
  65. package/utils/processInfo.js +0 -39
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Redis 助手 - JavaScript 版本
3
2
  * 提供 Redis 操作的便捷方法
4
3
  */
5
4
 
5
+ import { createError } from "../utils/error.js";
6
6
  import { Connect } from "./connect.js";
7
7
  import { Logger } from "./logger.js";
8
8
 
9
9
  /**
10
10
  * Redis 助手类
11
- * 约定:除构造函数外,方法默认不抛异常;失败时返回 null/false/0/[] 并记录日志。
11
+ * 约定:除构造函数与 ping 外,方法默认不抛异常;失败时返回 null/false/0/[] 并记录日志。
12
12
  */
13
13
  export class RedisHelper {
14
14
  /**
@@ -18,15 +18,27 @@ export class RedisHelper {
18
18
  constructor(prefix = "") {
19
19
  const client = Connect.getRedis();
20
20
  if (!client) {
21
- throw new Error("Redis 客户端未初始化,请先调用 Connect.connectRedis()", {
22
- cause: null,
23
- code: "runtime"
24
- });
21
+ throw createError("Redis 客户端未初始化,请先调用 Connect.connectRedis()", { code: "runtime" });
25
22
  }
26
23
  this.client = client;
27
24
  this.prefix = prefix ? `${prefix}:` : "";
28
25
  }
29
26
 
27
+ /**
28
+ * 吞错执行:失败记录日志并返回 fallback(不抛出)
29
+ * @param label - 操作名(用于日志文案)
30
+ * @param operation - 实际操作
31
+ * @param fallback - 失败返回值
32
+ */
33
+ async safeCall(label, operation, fallback) {
34
+ try {
35
+ return await operation();
36
+ } catch (error) {
37
+ Logger.error(`Redis ${label} 错误`, error);
38
+ return fallback;
39
+ }
40
+ }
41
+
30
42
  /**
31
43
  * 设置对象到 Redis
32
44
  * @param key - 键名
@@ -35,19 +47,15 @@ export class RedisHelper {
35
47
  * @returns 操作结果
36
48
  */
37
49
  async setObject(key, obj, ttl = null) {
38
- try {
39
- const data = JSON.stringify(obj);
40
- const pkey = `${this.prefix}${key}`;
41
-
42
- if (ttl) {
43
- return await this.client.setex(pkey, ttl, data);
44
- }
45
-
46
- return await this.client.set(pkey, data);
47
- } catch (error) {
48
- Logger.error("Redis setObject 错误", error);
49
- return null;
50
- }
50
+ return this.safeCall(
51
+ "setObject",
52
+ async () => {
53
+ const data = JSON.stringify(obj);
54
+ const pkey = `${this.prefix}${key}`;
55
+ return ttl ? this.client.setex(pkey, ttl, data) : this.client.set(pkey, data);
56
+ },
57
+ null
58
+ );
51
59
  }
52
60
 
53
61
  /**
@@ -56,14 +64,15 @@ export class RedisHelper {
56
64
  * @returns 对象或 null
57
65
  */
58
66
  async getObject(key) {
59
- try {
60
- const pkey = `${this.prefix}${key}`;
61
- const data = await this.client.get(pkey);
62
- return data ? JSON.parse(data) : null;
63
- } catch (error) {
64
- Logger.error("Redis getObject 错误", error);
65
- return null;
66
- }
67
+ return this.safeCall(
68
+ "getObject",
69
+ async () => {
70
+ const pkey = `${this.prefix}${key}`;
71
+ const data = await this.client.get(pkey);
72
+ return data ? JSON.parse(data) : null;
73
+ },
74
+ null
75
+ );
67
76
  }
68
77
 
69
78
  /**
@@ -71,12 +80,10 @@ export class RedisHelper {
71
80
  * @param key - 键名
72
81
  */
73
82
  async delObject(key) {
74
- try {
83
+ return this.safeCall("delObject", async () => {
75
84
  const pkey = `${this.prefix}${key}`;
76
85
  await this.client.del(pkey);
77
- } catch (error) {
78
- Logger.error("Redis delObject 错误", error);
79
- }
86
+ });
80
87
  }
81
88
 
82
89
  // ==================== ID 生成 ====================
@@ -112,17 +119,14 @@ export class RedisHelper {
112
119
  * @param ttl - 过期时间(秒)
113
120
  */
114
121
  async setString(key, value, ttl = null) {
115
- try {
116
- const pkey = `${this.prefix}${key}`;
117
- if (ttl) {
118
- return await this.client.setex(pkey, ttl, value);
119
- }
120
-
121
- return await this.client.set(pkey, value);
122
- } catch (error) {
123
- Logger.error("Redis setString 错误", error);
124
- return null;
125
- }
122
+ return this.safeCall(
123
+ "setString",
124
+ async () => {
125
+ const pkey = `${this.prefix}${key}`;
126
+ return ttl ? this.client.setex(pkey, ttl, value) : this.client.set(pkey, value);
127
+ },
128
+ null
129
+ );
126
130
  }
127
131
 
128
132
  /**
@@ -130,13 +134,14 @@ export class RedisHelper {
130
134
  * @param key - 键名
131
135
  */
132
136
  async getString(key) {
133
- try {
134
- const pkey = `${this.prefix}${key}`;
135
- return await this.client.get(pkey);
136
- } catch (error) {
137
- Logger.error("Redis getString 错误", error);
138
- return null;
139
- }
137
+ return this.safeCall(
138
+ "getString",
139
+ async () => {
140
+ const pkey = `${this.prefix}${key}`;
141
+ return this.client.get(pkey);
142
+ },
143
+ null
144
+ );
140
145
  }
141
146
 
142
147
  /**
@@ -145,13 +150,14 @@ export class RedisHelper {
145
150
  * @returns 是否存在(true/false)
146
151
  */
147
152
  async exists(key) {
148
- try {
149
- const pkey = `${this.prefix}${key}`;
150
- return await this.client.exists(pkey);
151
- } catch (error) {
152
- Logger.error("Redis exists 错误", error);
153
- return false;
154
- }
153
+ return this.safeCall(
154
+ "exists",
155
+ async () => {
156
+ const pkey = `${this.prefix}${key}`;
157
+ return this.client.exists(pkey);
158
+ },
159
+ false
160
+ );
155
161
  }
156
162
 
157
163
  /**
@@ -160,29 +166,14 @@ export class RedisHelper {
160
166
  * @returns 自增后的值
161
167
  */
162
168
  async incr(key) {
163
- try {
164
- const pkey = `${this.prefix}${key}`;
165
- return await this.client.incr(pkey);
166
- } catch (error) {
167
- Logger.error("Redis incr 错误", error);
168
- return 0;
169
- }
170
- }
171
-
172
- /**
173
- * 原子按指定值自增
174
- * @param key - 键名
175
- * @param value - 自增值
176
- * @returns 自增后的值
177
- */
178
- async incrBy(key, value) {
179
- try {
180
- const pkey = `${this.prefix}${key}`;
181
- return await this.client.incrby(pkey, value);
182
- } catch (error) {
183
- Logger.error("Redis incrBy 错误", error);
184
- return 0;
185
- }
169
+ return this.safeCall(
170
+ "incr",
171
+ async () => {
172
+ const pkey = `${this.prefix}${key}`;
173
+ return this.client.incr(pkey);
174
+ },
175
+ 0
176
+ );
186
177
  }
187
178
 
188
179
  /**
@@ -192,17 +183,18 @@ export class RedisHelper {
192
183
  * @returns 自增后的值
193
184
  */
194
185
  async incrWithExpire(key, seconds) {
195
- try {
196
- const pkey = `${this.prefix}${key}`;
197
- const res = await this.client.incr(pkey);
198
- if (res === 1) {
199
- await this.client.expire(pkey, seconds);
200
- }
201
- return res;
202
- } catch (error) {
203
- Logger.error("Redis incrWithExpire 错误", error);
204
- return 0;
205
- }
186
+ return this.safeCall(
187
+ "incrWithExpire",
188
+ async () => {
189
+ const pkey = `${this.prefix}${key}`;
190
+ const res = await this.client.incr(pkey);
191
+ if (res === 1) {
192
+ await this.client.expire(pkey, seconds);
193
+ }
194
+ return res;
195
+ },
196
+ 0
197
+ );
206
198
  }
207
199
 
208
200
  /**
@@ -211,13 +203,14 @@ export class RedisHelper {
211
203
  * @param seconds - 秒数
212
204
  */
213
205
  async expire(key, seconds) {
214
- try {
215
- const pkey = `${this.prefix}${key}`;
216
- return await this.client.expire(pkey, seconds);
217
- } catch (error) {
218
- Logger.error("Redis expire 错误", error);
219
- return 0;
220
- }
206
+ return this.safeCall(
207
+ "expire",
208
+ async () => {
209
+ const pkey = `${this.prefix}${key}`;
210
+ return this.client.expire(pkey, seconds);
211
+ },
212
+ 0
213
+ );
221
214
  }
222
215
 
223
216
  /**
@@ -225,32 +218,14 @@ export class RedisHelper {
225
218
  * @param key - 键名
226
219
  */
227
220
  async ttl(key) {
228
- try {
229
- const pkey = `${this.prefix}${key}`;
230
- return await this.client.ttl(pkey);
231
- } catch (error) {
232
- Logger.error("Redis ttl 错误", error);
233
- return -1;
234
- }
235
- }
236
-
237
- /**
238
- * 批量获取剩余过期时间(利用 Bun Redis 自动管道优化)
239
- * @param keys - 键名数组
240
- * @returns TTL 数组(-2 表示键不存在,-1 表示无过期时间)
241
- */
242
- async ttlBatch(keys) {
243
- if (keys.length === 0) {
244
- return [];
245
- }
246
-
247
- try {
248
- const results = await Promise.all(keys.map((key) => this.ttl(key)));
249
- return results;
250
- } catch (error) {
251
- Logger.error("Redis ttlBatch 错误", error);
252
- return keys.map(() => -1);
253
- }
221
+ return this.safeCall(
222
+ "ttl",
223
+ async () => {
224
+ const pkey = `${this.prefix}${key}`;
225
+ return this.client.ttl(pkey);
226
+ },
227
+ -1
228
+ );
254
229
  }
255
230
 
256
231
  /**
@@ -260,19 +235,20 @@ export class RedisHelper {
260
235
  * @returns 成功添加的成员数量
261
236
  */
262
237
  async sadd(key, members) {
263
- try {
264
- if (members.length === 0) return 0;
265
-
266
- const pkey = `${this.prefix}${key}`;
267
- const args = [pkey];
268
- for (const member of members) {
269
- args.push(member);
270
- }
271
- return await this.client.sadd.apply(this.client, args);
272
- } catch (error) {
273
- Logger.error("Redis sadd 错误", error);
274
- return 0;
275
- }
238
+ return this.safeCall(
239
+ "sadd",
240
+ async () => {
241
+ if (members.length === 0) return 0;
242
+
243
+ const pkey = `${this.prefix}${key}`;
244
+ const args = [pkey];
245
+ for (const member of members) {
246
+ args.push(member);
247
+ }
248
+ return this.client.sadd.apply(this.client, args);
249
+ },
250
+ 0
251
+ );
276
252
  }
277
253
 
278
254
  /**
@@ -282,28 +258,29 @@ export class RedisHelper {
282
258
  * @returns 是否存在(true/false)
283
259
  */
284
260
  async sismember(key, member) {
285
- try {
286
- const pkey = `${this.prefix}${key}`;
287
- return await this.client.sismember(pkey, member);
288
- } catch (error) {
289
- Logger.error("Redis sismember 错误", error);
290
- return false;
291
- }
261
+ return this.safeCall(
262
+ "sismember",
263
+ async () => {
264
+ const pkey = `${this.prefix}${key}`;
265
+ return this.client.sismember(pkey, member);
266
+ },
267
+ false
268
+ );
292
269
  }
293
270
 
294
271
  /**
295
272
  * 获取 Set 的成员数量
296
273
  * @param key - 键名
297
- * @returns 成员数量
298
274
  */
299
275
  async scard(key) {
300
- try {
301
- const pkey = `${this.prefix}${key}`;
302
- return await this.client.scard(pkey);
303
- } catch (error) {
304
- Logger.error("Redis scard 错误", error);
305
- return 0;
306
- }
276
+ return this.safeCall(
277
+ "scard",
278
+ async () => {
279
+ const pkey = `${this.prefix}${key}`;
280
+ return this.client.scard(pkey);
281
+ },
282
+ 0
283
+ );
307
284
  }
308
285
 
309
286
  /**
@@ -312,35 +289,14 @@ export class RedisHelper {
312
289
  * @returns 成员数组
313
290
  */
314
291
  async smembers(key) {
315
- try {
316
- const pkey = `${this.prefix}${key}`;
317
- return await this.client.smembers(pkey);
318
- } catch (error) {
319
- Logger.error("Redis smembers 错误", error);
320
- return [];
321
- }
322
- }
323
-
324
- /**
325
- * 从 Set 中删除一个或多个成员
326
- * @param key - 键名
327
- * @param members - 成员数组
328
- * @returns 删除的成员数量
329
- */
330
- async srem(key, members) {
331
- try {
332
- if (members.length === 0) return 0;
333
-
334
- const pkey = `${this.prefix}${key}`;
335
- const args = [pkey];
336
- for (const member of members) {
337
- args.push(member);
338
- }
339
- return await this.client.srem.apply(this.client, args);
340
- } catch (error) {
341
- Logger.error("Redis srem 错误", error);
342
- return 0;
343
- }
292
+ return this.safeCall(
293
+ "smembers",
294
+ async () => {
295
+ const pkey = `${this.prefix}${key}`;
296
+ return this.client.smembers(pkey);
297
+ },
298
+ []
299
+ );
344
300
  }
345
301
 
346
302
  /**
@@ -349,128 +305,18 @@ export class RedisHelper {
349
305
  * @returns 成功添加的总成员数量
350
306
  */
351
307
  async saddBatch(items) {
352
- if (items.length === 0) {
353
- return 0;
354
- }
355
-
356
- try {
357
- const results = await Promise.all(items.map((item) => this.sadd(item.key, item.members)));
358
- return results.reduce((sum, count) => sum + count, 0);
359
- } catch (error) {
360
- Logger.error("Redis saddBatch 错误", error);
361
- return 0;
362
- }
363
- }
364
-
365
- /**
366
- * 批量检查成员是否在 Set 中(利用 Bun Redis 自动管道优化)
367
- * @param items - [{ key, member }] 数组
368
- * @returns 布尔数组(true 表示存在,false 表示不存在)
369
- */
370
- async sismemberBatch(items) {
371
- if (items.length === 0) {
372
- return [];
373
- }
374
-
375
- try {
376
- return await Promise.all(items.map((item) => this.sismember(item.key, item.member)));
377
- } catch (error) {
378
- Logger.error("Redis sismemberBatch 错误", error);
379
- return items.map(() => false);
380
- }
381
- }
382
-
383
- /**
384
- * 向有序集合添加成员
385
- * @param key - 键名
386
- * @param items - [{ score, member }] 数组
387
- * @returns 成功添加的成员数量
388
- */
389
- async zadd(key, items) {
390
- try {
391
- if (items.length === 0) {
392
- return 0;
393
- }
394
-
395
- const pkey = `${this.prefix}${key}`;
396
- const args = [pkey];
397
-
398
- for (const item of items) {
399
- const score = Number(item.score);
400
- const member = String(item.member);
401
-
402
- if (!Number.isFinite(score) || member.length === 0) {
403
- continue;
308
+ return this.safeCall(
309
+ "saddBatch",
310
+ async () => {
311
+ if (items.length === 0) {
312
+ return 0;
404
313
  }
405
314
 
406
- args.push(score);
407
- args.push(member);
408
- }
409
-
410
- if (args.length <= 1) {
411
- return 0;
412
- }
413
-
414
- return await this.client.zadd.apply(this.client, args);
415
- } catch (error) {
416
- Logger.error("Redis zadd 错误", error);
417
- return 0;
418
- }
419
- }
420
-
421
- /**
422
- * 获取有序集合成员数量
423
- * @param key - 键名
424
- */
425
- async zcard(key) {
426
- try {
427
- const pkey = `${this.prefix}${key}`;
428
- return await this.client.zcard(pkey);
429
- } catch (error) {
430
- Logger.error("Redis zcard 错误", error);
431
- return 0;
432
- }
433
- }
434
-
435
- /**
436
- * 按 score 区间删除有序集合成员
437
- * @param key - 键名
438
- * @param min - 最小分值
439
- * @param max - 最大分值
440
- */
441
- async zremrangebyscore(key, min, max) {
442
- try {
443
- const pkey = `${this.prefix}${key}`;
444
- return await this.client.zremrangebyscore(pkey, min, max);
445
- } catch (error) {
446
- Logger.error("Redis zremrangebyscore 错误", error);
447
- return 0;
448
- }
449
- }
450
-
451
- /**
452
- * 从有序集合删除一个或多个成员
453
- * @param key - 键名
454
- * @param members - 成员数组
455
- */
456
- async zrem(key, members) {
457
- try {
458
- if (members.length === 0) {
459
- return 0;
460
- }
461
-
462
- const pkey = `${this.prefix}${key}`;
463
- const args = [pkey];
464
-
465
- for (const member of members) {
466
- args.push(String(member));
467
- }
468
-
469
- return await this.client.zrem.apply(this.client, args);
470
- } catch (error) {
471
- Logger.error("Redis zrem 错误", error);
472
- return 0;
473
- }
315
+ const results = await Promise.all(items.map((item) => this.sadd(item.key, item.members)));
316
+ return results.reduce((sum, count) => sum + count, 0);
317
+ },
318
+ 0
319
+ );
474
320
  }
475
321
 
476
322
  /**
@@ -479,13 +325,14 @@ export class RedisHelper {
479
325
  * @returns 删除的键数量
480
326
  */
481
327
  async del(key) {
482
- try {
483
- const pkey = `${this.prefix}${key}`;
484
- return await this.client.del(pkey);
485
- } catch (error) {
486
- Logger.error("Redis del 错误", error);
487
- return 0;
488
- }
328
+ return this.safeCall(
329
+ "del",
330
+ async () => {
331
+ const pkey = `${this.prefix}${key}`;
332
+ return this.client.del(pkey);
333
+ },
334
+ 0
335
+ );
489
336
  }
490
337
 
491
338
  /**
@@ -494,97 +341,23 @@ export class RedisHelper {
494
341
  * @returns 成功删除的键数量
495
342
  */
496
343
  async delBatch(keys) {
497
- if (keys.length === 0) {
498
- return 0;
499
- }
500
-
501
- try {
502
- const results = await Promise.all(
503
- keys.map((key) => {
504
- const pkey = `${this.prefix}${key}`;
505
- return this.client.del(pkey);
506
- })
507
- );
508
- return results.reduce((sum, count) => sum + count, 0);
509
- } catch (error) {
510
- Logger.error("Redis delBatch 错误", error);
511
- return 0;
512
- }
513
- }
514
-
515
- /**
516
- * 批量设置对象(利用 Bun Redis 自动管道优化)
517
- * @param items - 键值对数组 [{ key, value, ttl? }]
518
- * @returns 成功设置的数量
519
- */
520
- async setBatch(items) {
521
- if (items.length === 0) {
522
- return 0;
523
- }
524
-
525
- try {
526
- const results = await Promise.all(items.map((item) => this.setObject(item.key, item.value, item.ttl ?? null)));
527
- return results.filter((r) => r !== null).length;
528
- } catch (error) {
529
- Logger.error("Redis setBatch 错误", error);
530
- return 0;
531
- }
532
- }
533
-
534
- /**
535
- * 批量获取对象(利用 Bun Redis 自动管道优化)
536
- * @param keys - 键名数组
537
- * @returns 对象数组(不存在的键返回 null)
538
- */
539
- async getBatch(keys) {
540
- if (keys.length === 0) {
541
- return [];
542
- }
543
-
544
- try {
545
- const results = await Promise.all(keys.map((key) => this.getObject(key)));
546
- return results;
547
- } catch (error) {
548
- Logger.error("Redis getBatch 错误", error);
549
- return keys.map(() => null);
550
- }
551
- }
552
-
553
- /**
554
- * 批量检查键是否存在(利用 Bun Redis 自动管道优化)
555
- * @param keys - 键名数组
556
- * @returns 布尔数组(true 表示存在,false 表示不存在)
557
- */
558
- async existsBatch(keys) {
559
- if (keys.length === 0) {
560
- return [];
561
- }
562
-
563
- try {
564
- return await Promise.all(keys.map((key) => this.exists(key)));
565
- } catch (error) {
566
- Logger.error("Redis existsBatch 错误", error);
567
- return keys.map(() => false);
568
- }
569
- }
570
-
571
- /**
572
- * 批量设置过期时间(利用 Bun Redis 自动管道优化)
573
- * @param items - 键名和过期时间数组 [{ key, seconds }]
574
- * @returns 成功设置的数量
575
- */
576
- async expireBatch(items) {
577
- if (items.length === 0) {
578
- return 0;
579
- }
344
+ return this.safeCall(
345
+ "delBatch",
346
+ async () => {
347
+ if (keys.length === 0) {
348
+ return 0;
349
+ }
580
350
 
581
- try {
582
- const results = await Promise.all(items.map((item) => this.expire(item.key, item.seconds)));
583
- return results.filter((r) => r > 0).length;
584
- } catch (error) {
585
- Logger.error("Redis expireBatch 错误", error);
586
- return 0;
587
- }
351
+ const results = await Promise.all(
352
+ keys.map((key) => {
353
+ const pkey = `${this.prefix}${key}`;
354
+ return this.client.del(pkey);
355
+ })
356
+ );
357
+ return results.reduce((sum, count) => sum + count, 0);
358
+ },
359
+ 0
360
+ );
588
361
  }
589
362
 
590
363
  /**
@@ -592,29 +365,27 @@ export class RedisHelper {
592
365
  * @param section - 可选 section(如 "server")
593
366
  */
594
367
  async info(section) {
595
- try {
596
- const client = this.client;
368
+ return this.safeCall(
369
+ "info",
370
+ async () => {
371
+ const client = this.client;
597
372
 
598
- if (typeof client.info === "function") {
599
- return await client.info(section);
600
- }
373
+ if (typeof client.info === "function") {
374
+ return client.info(section);
375
+ }
601
376
 
602
- if (typeof client.send === "function") {
603
- return await client.send("INFO", section ? [String(section)] : []);
604
- }
377
+ if (typeof client.send === "function") {
378
+ return client.send("INFO", section ? [String(section)] : []);
379
+ }
605
380
 
606
- throw new Error("Redis info 不支持", {
607
- cause: null,
608
- code: "runtime"
609
- });
610
- } catch (error) {
611
- Logger.error("Redis info 错误", error);
612
- return "";
613
- }
381
+ throw createError("Redis info 不支持", { code: "runtime" });
382
+ },
383
+ ""
384
+ );
614
385
  }
615
386
 
616
387
  /**
617
- * 测试 Redis 连接
388
+ * 测试 Redis 连接(异常时抛出,供调用方感知连接状态)
618
389
  * @returns ping 响应结果
619
390
  */
620
391
  async ping() {
@@ -622,12 +393,7 @@ export class RedisHelper {
622
393
  return await this.client.ping();
623
394
  } catch (error) {
624
395
  Logger.error("Redis ping 错误", error);
625
- throw new Error("Redis ping 错误", {
626
- cause: error,
627
- code: "runtime",
628
- subsystem: "redis",
629
- operation: "ping"
630
- });
396
+ throw createError("Redis ping 错误", { cause: error, code: "runtime", subsystem: "redis", operation: "ping" });
631
397
  }
632
398
  }
633
399
  }