befly 3.10.17 → 3.10.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -307
- package/dist/befly.config.d.ts +7 -0
- package/{befly.config.ts → dist/befly.config.js} +8 -31
- package/dist/checks/checkApi.d.ts +1 -0
- package/{checks/checkApi.ts → dist/checks/checkApi.js} +10 -27
- package/dist/checks/checkHook.d.ts +1 -0
- package/{checks/checkHook.ts → dist/checks/checkHook.js} +10 -19
- package/dist/checks/checkMenu.d.ts +7 -0
- package/{checks/checkMenu.ts → dist/checks/checkMenu.js} +15 -50
- package/dist/checks/checkPlugin.d.ts +1 -0
- package/{checks/checkPlugin.ts → dist/checks/checkPlugin.js} +10 -19
- package/dist/checks/checkTable.d.ts +6 -0
- package/{checks/checkTable.ts → dist/checks/checkTable.js} +16 -40
- package/dist/configs/presetFields.d.ts +4 -0
- package/{configs/presetFields.ts → dist/configs/presetFields.js} +1 -1
- package/dist/configs/presetRegexp.d.ts +145 -0
- package/{utils/regex.ts → dist/configs/presetRegexp.js} +8 -31
- package/dist/hooks/auth.d.ts +5 -0
- package/{hooks/auth.ts → dist/hooks/auth.js} +5 -9
- package/dist/hooks/cors.d.ts +9 -0
- package/{hooks/cors.ts → dist/hooks/cors.js} +2 -12
- package/dist/hooks/parser.d.ts +12 -0
- package/{hooks/parser.ts → dist/hooks/parser.js} +27 -42
- package/dist/hooks/permission.d.ts +12 -0
- package/{hooks/permission.ts → dist/hooks/permission.js} +11 -22
- package/dist/hooks/validator.d.ts +9 -0
- package/{hooks/validator.ts → dist/hooks/validator.js} +5 -12
- package/dist/lib/asyncContext.d.ts +21 -0
- package/dist/lib/asyncContext.js +27 -0
- package/dist/lib/cacheHelper.d.ts +95 -0
- package/{lib/cacheHelper.ts → dist/lib/cacheHelper.js} +43 -103
- package/dist/lib/cacheKeys.d.ts +23 -0
- package/{lib/cacheKeys.ts → dist/lib/cacheKeys.js} +5 -10
- package/dist/lib/cipher.d.ts +153 -0
- package/{lib/cipher.ts → dist/lib/cipher.js} +23 -44
- package/dist/lib/connect.d.ts +91 -0
- package/{lib/connect.ts → dist/lib/connect.js} +46 -87
- package/dist/lib/dbDialect.d.ts +87 -0
- package/{lib/dbDialect.ts → dist/lib/dbDialect.js} +32 -112
- package/dist/lib/dbHelper.d.ts +204 -0
- package/{lib/dbHelper.ts → dist/lib/dbHelper.js} +73 -230
- package/dist/lib/dbUtils.d.ts +68 -0
- package/{lib/dbUtils.ts → dist/lib/dbUtils.js} +49 -123
- package/dist/lib/jwt.d.ts +13 -0
- package/{lib/jwt.ts → dist/lib/jwt.js} +11 -32
- package/dist/lib/logger.d.ts +32 -0
- package/{lib/logger.ts → dist/lib/logger.js} +201 -278
- package/dist/lib/redisHelper.d.ts +185 -0
- package/{lib/redisHelper.ts → dist/lib/redisHelper.js} +95 -139
- package/dist/lib/sqlBuilder.d.ts +160 -0
- package/{lib/sqlBuilder.ts → dist/lib/sqlBuilder.js} +131 -277
- package/dist/lib/sqlCheck.d.ts +23 -0
- package/{lib/sqlCheck.ts → dist/lib/sqlCheck.js} +24 -41
- package/dist/lib/validator.d.ts +45 -0
- package/{lib/validator.ts → dist/lib/validator.js} +43 -60
- package/dist/loader/loadApis.d.ts +12 -0
- package/{loader/loadApis.ts → dist/loader/loadApis.js} +7 -17
- package/dist/loader/loadHooks.d.ts +8 -0
- package/{loader/loadHooks.ts → dist/loader/loadHooks.js} +5 -19
- package/dist/loader/loadPlugins.d.ts +8 -0
- package/{loader/loadPlugins.ts → dist/loader/loadPlugins.js} +8 -20
- package/dist/main.d.ts +26 -0
- package/{main.ts → dist/main.js} +39 -78
- package/dist/paths.d.ts +93 -0
- package/{paths.ts → dist/paths.js} +6 -19
- package/dist/plugins/cache.d.ts +14 -0
- package/{plugins/cache.ts → dist/plugins/cache.js} +4 -11
- package/dist/plugins/cipher.d.ts +10 -0
- package/{plugins/cipher.ts → dist/plugins/cipher.js} +1 -5
- package/dist/plugins/config.d.ts +10 -0
- package/dist/plugins/config.js +6 -0
- package/dist/plugins/db.d.ts +14 -0
- package/{plugins/db.ts → dist/plugins/db.js} +5 -13
- package/dist/plugins/jwt.d.ts +10 -0
- package/{plugins/jwt.ts → dist/plugins/jwt.js} +2 -7
- package/dist/plugins/logger.d.ts +28 -0
- package/{plugins/logger.ts → dist/plugins/logger.js} +2 -7
- package/dist/plugins/redis.d.ts +14 -0
- package/{plugins/redis.ts → dist/plugins/redis.js} +4 -9
- package/dist/plugins/tool.d.ts +79 -0
- package/{plugins/tool.ts → dist/plugins/tool.js} +7 -30
- package/dist/router/api.d.ts +14 -0
- package/dist/router/api.js +107 -0
- package/dist/router/static.d.ts +9 -0
- package/{router/static.ts → dist/router/static.js} +17 -31
- package/dist/scripts/ensureDist.d.ts +1 -0
- package/dist/scripts/ensureDist.js +80 -0
- package/dist/sync/syncApi.d.ts +3 -0
- package/{sync/syncApi.ts → dist/sync/syncApi.js} +33 -53
- package/dist/sync/syncCache.d.ts +2 -0
- package/{sync/syncCache.ts → dist/sync/syncCache.js} +1 -6
- package/dist/sync/syncDev.d.ts +6 -0
- package/{sync/syncDev.ts → dist/sync/syncDev.js} +27 -60
- package/dist/sync/syncMenu.d.ts +14 -0
- package/{sync/syncMenu.ts → dist/sync/syncMenu.js} +61 -121
- package/dist/sync/syncTable.d.ts +151 -0
- package/{sync/syncTable.ts → dist/sync/syncTable.js} +168 -375
- package/{types → dist/types}/api.d.ts +12 -51
- package/dist/types/api.js +4 -0
- package/{types → dist/types}/befly.d.ts +32 -223
- package/dist/types/befly.js +4 -0
- package/{types → dist/types}/cache.d.ts +7 -15
- package/dist/types/cache.js +4 -0
- package/dist/types/cipher.d.ts +27 -0
- package/dist/types/cipher.js +7 -0
- package/{types → dist/types}/common.d.ts +8 -33
- package/dist/types/common.js +5 -0
- package/{types → dist/types}/context.d.ts +3 -5
- package/dist/types/context.js +4 -0
- package/{types → dist/types}/crypto.d.ts +0 -3
- package/dist/types/crypto.js +4 -0
- package/dist/types/database.d.ts +138 -0
- package/dist/types/database.js +4 -0
- package/dist/types/hook.d.ts +15 -0
- package/dist/types/hook.js +6 -0
- package/dist/types/jwt.d.ts +75 -0
- package/dist/types/jwt.js +4 -0
- package/dist/types/logger.d.ts +47 -0
- package/dist/types/logger.js +6 -0
- package/dist/types/plugin.d.ts +14 -0
- package/dist/types/plugin.js +6 -0
- package/dist/types/redis.d.ts +71 -0
- package/dist/types/redis.js +4 -0
- package/{types/roleApisCache.ts → dist/types/roleApisCache.d.ts} +0 -2
- package/dist/types/roleApisCache.js +8 -0
- package/dist/types/sync.d.ts +92 -0
- package/dist/types/sync.js +4 -0
- package/dist/types/table.d.ts +34 -0
- package/dist/types/table.js +4 -0
- package/dist/types/validate.d.ts +67 -0
- package/dist/types/validate.js +4 -0
- package/dist/utils/arrayKeysToCamel.d.ts +13 -0
- package/{utils/arrayKeysToCamel.ts → dist/utils/arrayKeysToCamel.js} +4 -4
- package/dist/utils/calcPerfTime.d.ts +4 -0
- package/{utils/calcPerfTime.ts → dist/utils/calcPerfTime.js} +3 -3
- package/dist/utils/configTypes.d.ts +1 -0
- package/dist/utils/configTypes.js +1 -0
- package/dist/utils/convertBigIntFields.d.ts +11 -0
- package/{utils/convertBigIntFields.ts → dist/utils/convertBigIntFields.js} +5 -9
- package/dist/utils/cors.d.ts +8 -0
- package/{utils/cors.ts → dist/utils/cors.js} +1 -3
- package/dist/utils/disableMenusGlob.d.ts +13 -0
- package/{utils/disableMenusGlob.ts → dist/utils/disableMenusGlob.js} +9 -29
- package/dist/utils/fieldClear.d.ts +11 -0
- package/{utils/fieldClear.ts → dist/utils/fieldClear.js} +15 -33
- package/dist/utils/genShortId.d.ts +10 -0
- package/{utils/genShortId.ts → dist/utils/genShortId.js} +1 -1
- package/dist/utils/getClientIp.d.ts +6 -0
- package/{utils/getClientIp.ts → dist/utils/getClientIp.js} +1 -7
- package/dist/utils/importDefault.d.ts +1 -0
- package/dist/utils/importDefault.js +29 -0
- package/dist/utils/isDirentDirectory.d.ts +2 -0
- package/{utils/isDirentDirectory.ts → dist/utils/isDirentDirectory.js} +3 -8
- package/dist/utils/keysToCamel.d.ts +10 -0
- package/{utils/keysToCamel.ts → dist/utils/keysToCamel.js} +4 -5
- package/dist/utils/keysToSnake.d.ts +10 -0
- package/{utils/keysToSnake.ts → dist/utils/keysToSnake.js} +4 -5
- package/dist/utils/loadMenuConfigs.d.ts +5 -0
- package/{utils/loadMenuConfigs.ts → dist/utils/loadMenuConfigs.js} +22 -49
- package/dist/utils/pickFields.d.ts +4 -0
- package/{utils/pickFields.ts → dist/utils/pickFields.js} +2 -5
- package/dist/utils/process.d.ts +24 -0
- package/{utils/process.ts → dist/utils/process.js} +2 -18
- package/dist/utils/processFields.d.ts +4 -0
- package/{utils/processFields.ts → dist/utils/processFields.js} +4 -8
- package/dist/utils/regex.d.ts +145 -0
- package/{configs/presetRegexp.ts → dist/utils/regex.js} +8 -31
- package/dist/utils/response.d.ts +20 -0
- package/{utils/response.ts → dist/utils/response.js} +27 -48
- package/dist/utils/scanAddons.d.ts +17 -0
- package/{utils/scanAddons.ts → dist/utils/scanAddons.js} +4 -38
- package/dist/utils/scanConfig.d.ts +26 -0
- package/{utils/scanConfig.ts → dist/utils/scanConfig.js} +22 -59
- package/dist/utils/scanFiles.d.ts +30 -0
- package/{utils/scanFiles.ts → dist/utils/scanFiles.js} +25 -65
- package/dist/utils/scanSources.d.ts +10 -0
- package/{utils/scanSources.ts → dist/utils/scanSources.js} +16 -39
- package/dist/utils/sortModules.d.ts +28 -0
- package/{utils/sortModules.ts → dist/utils/sortModules.js} +24 -64
- package/dist/utils/sqlLog.d.ts +14 -0
- package/{utils/sqlLog.ts → dist/utils/sqlLog.js} +2 -14
- package/package.json +15 -32
- package/.gitignore +0 -0
- package/bunfig.toml +0 -3
- package/docs/README.md +0 -98
- package/docs/api/api.md +0 -1921
- package/docs/guide/examples.md +0 -926
- package/docs/guide/quickstart.md +0 -354
- package/docs/hooks/auth.md +0 -38
- package/docs/hooks/cors.md +0 -28
- package/docs/hooks/hook.md +0 -838
- package/docs/hooks/parser.md +0 -19
- package/docs/hooks/rateLimit.md +0 -47
- package/docs/infra/redis.md +0 -628
- package/docs/plugins/cipher.md +0 -61
- package/docs/plugins/database.md +0 -189
- package/docs/plugins/plugin.md +0 -986
- package/docs/reference/addon.md +0 -510
- package/docs/reference/config.md +0 -573
- package/docs/reference/logger.md +0 -495
- package/docs/reference/sync.md +0 -478
- package/docs/reference/table.md +0 -763
- package/docs/reference/validator.md +0 -620
- package/lib/asyncContext.ts +0 -43
- package/plugins/config.ts +0 -13
- package/router/api.ts +0 -130
- package/tsconfig.json +0 -54
- package/types/database.d.ts +0 -541
- package/types/hook.d.ts +0 -25
- package/types/jwt.d.ts +0 -118
- package/types/logger.d.ts +0 -65
- package/types/plugin.d.ts +0 -19
- package/types/redis.d.ts +0 -83
- package/types/sync.d.ts +0 -398
- package/types/table.d.ts +0 -216
- package/types/validate.d.ts +0 -69
- package/utils/configTypes.ts +0 -3
- package/utils/importDefault.ts +0 -21
|
@@ -2,27 +2,21 @@
|
|
|
2
2
|
* Redis 助手 - TypeScript 版本
|
|
3
3
|
* 提供 Redis 操作的便捷方法
|
|
4
4
|
*/
|
|
5
|
-
|
|
6
|
-
import { RedisClient } from "bun";
|
|
7
|
-
|
|
8
5
|
import { Connect } from "./connect.js";
|
|
9
6
|
import { Logger } from "./logger.js";
|
|
10
|
-
|
|
11
7
|
/**
|
|
12
8
|
* Redis 助手类
|
|
13
9
|
* 约定:除构造函数外,方法默认不抛异常;失败时返回 null/false/0/[] 并记录日志。
|
|
14
10
|
*/
|
|
15
11
|
export class RedisHelper {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
private readonly slowThresholdMs: number = 500;
|
|
20
|
-
|
|
12
|
+
client;
|
|
13
|
+
prefix;
|
|
14
|
+
slowThresholdMs = 500;
|
|
21
15
|
/**
|
|
22
16
|
* 构造函数
|
|
23
17
|
* @param prefix - Key 前缀
|
|
24
18
|
*/
|
|
25
|
-
constructor(prefix
|
|
19
|
+
constructor(prefix = "") {
|
|
26
20
|
const client = Connect.getRedis();
|
|
27
21
|
if (!client) {
|
|
28
22
|
throw new Error("Redis 客户端未初始化,请先调用 Connect.connectRedis()");
|
|
@@ -30,22 +24,18 @@ export class RedisHelper {
|
|
|
30
24
|
this.client = client;
|
|
31
25
|
this.prefix = prefix ? `${prefix}:` : "";
|
|
32
26
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Logger.warn(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
},
|
|
45
|
-
"🐌 Redis 慢操作"
|
|
46
|
-
);
|
|
27
|
+
logSlow(cmd, key, duration, extra = {}) {
|
|
28
|
+
if (duration <= this.slowThresholdMs)
|
|
29
|
+
return;
|
|
30
|
+
Logger.warn({
|
|
31
|
+
subsystem: "redis",
|
|
32
|
+
event: "slow",
|
|
33
|
+
duration: duration,
|
|
34
|
+
cmd: cmd,
|
|
35
|
+
key: key,
|
|
36
|
+
extra: extra
|
|
37
|
+
}, "🐌 Redis 慢操作");
|
|
47
38
|
}
|
|
48
|
-
|
|
49
39
|
/**
|
|
50
40
|
* 设置对象到 Redis
|
|
51
41
|
* @param key - 键名
|
|
@@ -53,107 +43,94 @@ export class RedisHelper {
|
|
|
53
43
|
* @param ttl - 过期时间(秒)
|
|
54
44
|
* @returns 操作结果
|
|
55
45
|
*/
|
|
56
|
-
async setObject
|
|
46
|
+
async setObject(key, obj, ttl = null) {
|
|
57
47
|
try {
|
|
58
48
|
const data = JSON.stringify(obj);
|
|
59
49
|
const pkey = `${this.prefix}${key}`;
|
|
60
|
-
|
|
61
50
|
const startTime = Date.now();
|
|
62
|
-
|
|
63
51
|
if (ttl) {
|
|
64
52
|
const res = await this.client.setex(pkey, ttl, data);
|
|
65
53
|
const duration = Date.now() - startTime;
|
|
66
54
|
this.logSlow("SETEX", pkey, duration, { ttl: ttl });
|
|
67
55
|
return res;
|
|
68
56
|
}
|
|
69
|
-
|
|
70
57
|
const res = await this.client.set(pkey, data);
|
|
71
58
|
const duration = Date.now() - startTime;
|
|
72
59
|
this.logSlow("SET", pkey, duration);
|
|
73
60
|
return res;
|
|
74
|
-
}
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
75
63
|
Logger.error({ err: error }, "Redis setObject 错误");
|
|
76
64
|
return null;
|
|
77
65
|
}
|
|
78
66
|
}
|
|
79
|
-
|
|
80
67
|
/**
|
|
81
68
|
* 从 Redis 获取对象
|
|
82
69
|
* @param key - 键名
|
|
83
70
|
* @returns 对象或 null
|
|
84
71
|
*/
|
|
85
|
-
async getObject
|
|
72
|
+
async getObject(key) {
|
|
86
73
|
try {
|
|
87
74
|
const pkey = `${this.prefix}${key}`;
|
|
88
|
-
|
|
89
75
|
const startTime = Date.now();
|
|
90
76
|
const data = await this.client.get(pkey);
|
|
91
77
|
const duration = Date.now() - startTime;
|
|
92
78
|
this.logSlow("GET", pkey, duration);
|
|
93
79
|
return data ? JSON.parse(data) : null;
|
|
94
|
-
}
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
95
82
|
Logger.error({ err: error }, "Redis getObject 错误");
|
|
96
83
|
return null;
|
|
97
84
|
}
|
|
98
85
|
}
|
|
99
|
-
|
|
100
86
|
/**
|
|
101
87
|
* 从 Redis 删除对象
|
|
102
88
|
* @param key - 键名
|
|
103
89
|
*/
|
|
104
|
-
async delObject(key
|
|
90
|
+
async delObject(key) {
|
|
105
91
|
try {
|
|
106
92
|
const pkey = `${this.prefix}${key}`;
|
|
107
|
-
|
|
108
93
|
const startTime = Date.now();
|
|
109
94
|
await this.client.del(pkey);
|
|
110
95
|
const duration = Date.now() - startTime;
|
|
111
96
|
this.logSlow("DEL", pkey, duration);
|
|
112
|
-
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
113
99
|
Logger.error({ err: error }, "Redis delObject 错误");
|
|
114
100
|
}
|
|
115
101
|
}
|
|
116
|
-
|
|
117
102
|
// ==================== ID 生成 ====================
|
|
118
103
|
// 注意:ID 生成功能强依赖 Redis 原子操作(INCR)保证分布式唯一性
|
|
119
104
|
// 主要被 DbHelper.insData 使用
|
|
120
|
-
|
|
121
105
|
/**
|
|
122
106
|
* 生成基于时间的唯一 ID
|
|
123
107
|
* 格式: 毫秒时间戳(13位) + 3位后缀(100-999) = 16位纯数字
|
|
124
108
|
* 每毫秒起点基于时间戳偏移,后缀分布更均匀
|
|
125
109
|
* @returns 唯一 ID (16位纯数字)
|
|
126
110
|
*/
|
|
127
|
-
async genTimeID()
|
|
111
|
+
async genTimeID() {
|
|
128
112
|
const timestamp = Date.now();
|
|
129
113
|
const key = `${this.prefix}time_id:${timestamp}`;
|
|
130
|
-
|
|
131
114
|
const startTime = Date.now();
|
|
132
|
-
|
|
133
115
|
const counter = await this.client.incr(key);
|
|
134
116
|
if (counter === 1) {
|
|
135
117
|
await this.client.expire(key, 1);
|
|
136
118
|
}
|
|
137
|
-
|
|
138
119
|
const duration = Date.now() - startTime;
|
|
139
120
|
this.logSlow("INCR", key, duration, { expireSeconds: 1 });
|
|
140
|
-
|
|
141
121
|
// 基于时间戳偏移起点,后缀 100-999 循环
|
|
142
122
|
const suffix = 100 + (((timestamp % 900) + counter - 1) % 900);
|
|
143
|
-
|
|
144
123
|
return Number(`${timestamp}${suffix}`);
|
|
145
124
|
}
|
|
146
|
-
|
|
147
125
|
/**
|
|
148
126
|
* 设置字符串值
|
|
149
127
|
* @param key - 键名
|
|
150
128
|
* @param value - 值
|
|
151
129
|
* @param ttl - 过期时间(秒)
|
|
152
130
|
*/
|
|
153
|
-
async setString(key
|
|
131
|
+
async setString(key, value, ttl = null) {
|
|
154
132
|
try {
|
|
155
133
|
const pkey = `${this.prefix}${key}`;
|
|
156
|
-
|
|
157
134
|
const startTime = Date.now();
|
|
158
135
|
if (ttl) {
|
|
159
136
|
const res = await this.client.setex(pkey, ttl, value);
|
|
@@ -161,86 +138,81 @@ export class RedisHelper {
|
|
|
161
138
|
this.logSlow("SETEX", pkey, duration, { ttl: ttl });
|
|
162
139
|
return res;
|
|
163
140
|
}
|
|
164
|
-
|
|
165
141
|
const res = await this.client.set(pkey, value);
|
|
166
142
|
const duration = Date.now() - startTime;
|
|
167
143
|
this.logSlow("SET", pkey, duration);
|
|
168
144
|
return res;
|
|
169
|
-
}
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
170
147
|
Logger.error({ err: error }, "Redis setString 错误");
|
|
171
148
|
return null;
|
|
172
149
|
}
|
|
173
150
|
}
|
|
174
|
-
|
|
175
151
|
/**
|
|
176
152
|
* 获取字符串值
|
|
177
153
|
* @param key - 键名
|
|
178
154
|
*/
|
|
179
|
-
async getString(key
|
|
155
|
+
async getString(key) {
|
|
180
156
|
try {
|
|
181
157
|
const pkey = `${this.prefix}${key}`;
|
|
182
|
-
|
|
183
158
|
const startTime = Date.now();
|
|
184
159
|
const res = await this.client.get(pkey);
|
|
185
160
|
const duration = Date.now() - startTime;
|
|
186
161
|
this.logSlow("GET", pkey, duration);
|
|
187
162
|
return res;
|
|
188
|
-
}
|
|
163
|
+
}
|
|
164
|
+
catch (error) {
|
|
189
165
|
Logger.error({ err: error }, "Redis getString 错误");
|
|
190
166
|
return null;
|
|
191
167
|
}
|
|
192
168
|
}
|
|
193
|
-
|
|
194
169
|
/**
|
|
195
170
|
* 检查键是否存在
|
|
196
171
|
* @param key - 键名
|
|
197
172
|
* @returns 是否存在(true/false)
|
|
198
173
|
*/
|
|
199
|
-
async exists(key
|
|
174
|
+
async exists(key) {
|
|
200
175
|
try {
|
|
201
176
|
const pkey = `${this.prefix}${key}`;
|
|
202
|
-
|
|
203
177
|
const startTime = Date.now();
|
|
204
178
|
const res = await this.client.exists(pkey);
|
|
205
179
|
const duration = Date.now() - startTime;
|
|
206
180
|
this.logSlow("EXISTS", pkey, duration);
|
|
207
181
|
return res;
|
|
208
|
-
}
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
209
184
|
Logger.error({ err: error }, "Redis exists 错误");
|
|
210
185
|
return false;
|
|
211
186
|
}
|
|
212
187
|
}
|
|
213
|
-
|
|
214
188
|
/**
|
|
215
189
|
* 原子自增
|
|
216
190
|
* @param key - 键名
|
|
217
191
|
* @returns 自增后的值
|
|
218
192
|
*/
|
|
219
|
-
async incr(key
|
|
193
|
+
async incr(key) {
|
|
220
194
|
try {
|
|
221
195
|
const pkey = `${this.prefix}${key}`;
|
|
222
|
-
|
|
223
196
|
const startTime = Date.now();
|
|
224
197
|
const res = await this.client.incr(pkey);
|
|
225
198
|
const duration = Date.now() - startTime;
|
|
226
199
|
this.logSlow("INCR", pkey, duration);
|
|
227
200
|
return res;
|
|
228
|
-
}
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
229
203
|
Logger.error({ err: error }, "Redis incr 错误");
|
|
230
204
|
return 0;
|
|
231
205
|
}
|
|
232
206
|
}
|
|
233
|
-
|
|
234
207
|
/**
|
|
235
208
|
* 原子自增并在首次自增时设置过期时间(常用于限流/计数)
|
|
236
209
|
* @param key - 键名
|
|
237
210
|
* @param seconds - 过期秒数
|
|
238
211
|
* @returns 自增后的值
|
|
239
212
|
*/
|
|
240
|
-
async incrWithExpire(key
|
|
213
|
+
async incrWithExpire(key, seconds) {
|
|
241
214
|
try {
|
|
242
215
|
const pkey = `${this.prefix}${key}`;
|
|
243
|
-
|
|
244
216
|
const startTime = Date.now();
|
|
245
217
|
const res = await this.client.incr(pkey);
|
|
246
218
|
if (res === 1) {
|
|
@@ -249,322 +221,306 @@ export class RedisHelper {
|
|
|
249
221
|
const duration = Date.now() - startTime;
|
|
250
222
|
this.logSlow("INCR", pkey, duration, { expireSeconds: seconds });
|
|
251
223
|
return res;
|
|
252
|
-
}
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
253
226
|
Logger.error({ err: error }, "Redis incrWithExpire 错误");
|
|
254
227
|
return 0;
|
|
255
228
|
}
|
|
256
229
|
}
|
|
257
|
-
|
|
258
230
|
/**
|
|
259
231
|
* 设置过期时间
|
|
260
232
|
* @param key - 键名
|
|
261
233
|
* @param seconds - 秒数
|
|
262
234
|
*/
|
|
263
|
-
async expire(key
|
|
235
|
+
async expire(key, seconds) {
|
|
264
236
|
try {
|
|
265
237
|
const pkey = `${this.prefix}${key}`;
|
|
266
|
-
|
|
267
238
|
const startTime = Date.now();
|
|
268
239
|
const res = await this.client.expire(pkey, seconds);
|
|
269
240
|
const duration = Date.now() - startTime;
|
|
270
241
|
this.logSlow("EXPIRE", pkey, duration, { seconds: seconds });
|
|
271
242
|
return res;
|
|
272
|
-
}
|
|
243
|
+
}
|
|
244
|
+
catch (error) {
|
|
273
245
|
Logger.error({ err: error }, "Redis expire 错误");
|
|
274
246
|
return 0;
|
|
275
247
|
}
|
|
276
248
|
}
|
|
277
|
-
|
|
278
249
|
/**
|
|
279
250
|
* 获取剩余过期时间
|
|
280
251
|
* @param key - 键名
|
|
281
252
|
*/
|
|
282
|
-
async ttl(key
|
|
253
|
+
async ttl(key) {
|
|
283
254
|
try {
|
|
284
255
|
const pkey = `${this.prefix}${key}`;
|
|
285
|
-
|
|
286
256
|
const startTime = Date.now();
|
|
287
257
|
const res = await this.client.ttl(pkey);
|
|
288
258
|
const duration = Date.now() - startTime;
|
|
289
259
|
this.logSlow("TTL", pkey, duration);
|
|
290
260
|
return res;
|
|
291
|
-
}
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
292
263
|
Logger.error({ err: error }, "Redis ttl 错误");
|
|
293
264
|
return -1;
|
|
294
265
|
}
|
|
295
266
|
}
|
|
296
|
-
|
|
297
267
|
/**
|
|
298
268
|
* 批量获取剩余过期时间(利用 Bun Redis 自动管道优化)
|
|
299
269
|
* @param keys - 键名数组
|
|
300
270
|
* @returns TTL 数组(-2 表示键不存在,-1 表示无过期时间)
|
|
301
271
|
*/
|
|
302
|
-
async ttlBatch(keys
|
|
272
|
+
async ttlBatch(keys) {
|
|
303
273
|
if (keys.length === 0) {
|
|
304
274
|
return [];
|
|
305
275
|
}
|
|
306
|
-
|
|
307
276
|
try {
|
|
308
277
|
const results = await Promise.all(keys.map((key) => this.ttl(key)));
|
|
309
278
|
return results;
|
|
310
|
-
}
|
|
279
|
+
}
|
|
280
|
+
catch (error) {
|
|
311
281
|
Logger.error({ err: error }, "Redis ttlBatch 错误");
|
|
312
282
|
return keys.map(() => -1);
|
|
313
283
|
}
|
|
314
284
|
}
|
|
315
|
-
|
|
316
285
|
/**
|
|
317
286
|
* 向 Set 中添加一个或多个成员
|
|
318
287
|
* @param key - 键名
|
|
319
288
|
* @param members - 成员数组
|
|
320
289
|
* @returns 成功添加的成员数量
|
|
321
290
|
*/
|
|
322
|
-
async sadd(key
|
|
291
|
+
async sadd(key, members) {
|
|
323
292
|
try {
|
|
324
|
-
if (members.length === 0)
|
|
325
|
-
|
|
293
|
+
if (members.length === 0)
|
|
294
|
+
return 0;
|
|
326
295
|
const pkey = `${this.prefix}${key}`;
|
|
327
|
-
|
|
328
296
|
const startTime = Date.now();
|
|
329
297
|
const res = await this.client.sadd(pkey, ...members);
|
|
330
298
|
const duration = Date.now() - startTime;
|
|
331
299
|
this.logSlow("SADD", pkey, duration, { membersCount: members.length });
|
|
332
300
|
return res;
|
|
333
|
-
}
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
334
303
|
Logger.error({ err: error }, "Redis sadd 错误");
|
|
335
304
|
return 0;
|
|
336
305
|
}
|
|
337
306
|
}
|
|
338
|
-
|
|
339
307
|
/**
|
|
340
308
|
* 判断成员是否在 Set 中
|
|
341
309
|
* @param key - 键名
|
|
342
310
|
* @param member - 成员
|
|
343
311
|
* @returns 是否存在(true/false)
|
|
344
312
|
*/
|
|
345
|
-
async sismember(key
|
|
313
|
+
async sismember(key, member) {
|
|
346
314
|
try {
|
|
347
315
|
const pkey = `${this.prefix}${key}`;
|
|
348
|
-
|
|
349
316
|
const startTime = Date.now();
|
|
350
317
|
const res = await this.client.sismember(pkey, member);
|
|
351
318
|
const duration = Date.now() - startTime;
|
|
352
319
|
this.logSlow("SISMEMBER", pkey, duration);
|
|
353
320
|
return res;
|
|
354
|
-
}
|
|
321
|
+
}
|
|
322
|
+
catch (error) {
|
|
355
323
|
Logger.error({ err: error }, "Redis sismember 错误");
|
|
356
324
|
return false;
|
|
357
325
|
}
|
|
358
326
|
}
|
|
359
|
-
|
|
360
327
|
/**
|
|
361
328
|
* 获取 Set 的成员数量
|
|
362
329
|
* @param key - 键名
|
|
363
330
|
* @returns 成员数量
|
|
364
331
|
*/
|
|
365
|
-
async scard(key
|
|
332
|
+
async scard(key) {
|
|
366
333
|
try {
|
|
367
334
|
const pkey = `${this.prefix}${key}`;
|
|
368
|
-
|
|
369
335
|
const startTime = Date.now();
|
|
370
336
|
const res = await this.client.scard(pkey);
|
|
371
337
|
const duration = Date.now() - startTime;
|
|
372
338
|
this.logSlow("SCARD", pkey, duration);
|
|
373
339
|
return res;
|
|
374
|
-
}
|
|
340
|
+
}
|
|
341
|
+
catch (error) {
|
|
375
342
|
Logger.error({ err: error }, "Redis scard 错误");
|
|
376
343
|
return 0;
|
|
377
344
|
}
|
|
378
345
|
}
|
|
379
|
-
|
|
380
346
|
/**
|
|
381
347
|
* 获取 Set 的所有成员
|
|
382
348
|
* @param key - 键名
|
|
383
349
|
* @returns 成员数组
|
|
384
350
|
*/
|
|
385
|
-
async smembers(key
|
|
351
|
+
async smembers(key) {
|
|
386
352
|
try {
|
|
387
353
|
const pkey = `${this.prefix}${key}`;
|
|
388
|
-
|
|
389
354
|
const startTime = Date.now();
|
|
390
355
|
const res = await this.client.smembers(pkey);
|
|
391
356
|
const duration = Date.now() - startTime;
|
|
392
357
|
this.logSlow("SMEMBERS", pkey, duration);
|
|
393
358
|
return res;
|
|
394
|
-
}
|
|
359
|
+
}
|
|
360
|
+
catch (error) {
|
|
395
361
|
Logger.error({ err: error }, "Redis smembers 错误");
|
|
396
362
|
return [];
|
|
397
363
|
}
|
|
398
364
|
}
|
|
399
|
-
|
|
400
365
|
/**
|
|
401
366
|
* 批量向多个 Set 添加成员(利用 Bun Redis 自动管道优化)
|
|
402
367
|
* @param items - [{ key, members }] 数组
|
|
403
368
|
* @returns 成功添加的总成员数量
|
|
404
369
|
*/
|
|
405
|
-
async saddBatch(items
|
|
370
|
+
async saddBatch(items) {
|
|
406
371
|
if (items.length === 0) {
|
|
407
372
|
return 0;
|
|
408
373
|
}
|
|
409
|
-
|
|
410
374
|
try {
|
|
411
375
|
const results = await Promise.all(items.map((item) => this.sadd(item.key, item.members)));
|
|
412
376
|
return results.reduce((sum, count) => sum + count, 0);
|
|
413
|
-
}
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
414
379
|
Logger.error({ err: error }, "Redis saddBatch 错误");
|
|
415
380
|
return 0;
|
|
416
381
|
}
|
|
417
382
|
}
|
|
418
|
-
|
|
419
383
|
/**
|
|
420
384
|
* 批量检查成员是否在 Set 中(利用 Bun Redis 自动管道优化)
|
|
421
385
|
* @param items - [{ key, member }] 数组
|
|
422
386
|
* @returns 布尔数组(true 表示存在,false 表示不存在)
|
|
423
387
|
*/
|
|
424
|
-
async sismemberBatch(items
|
|
388
|
+
async sismemberBatch(items) {
|
|
425
389
|
if (items.length === 0) {
|
|
426
390
|
return [];
|
|
427
391
|
}
|
|
428
|
-
|
|
429
392
|
try {
|
|
430
393
|
return await Promise.all(items.map((item) => this.sismember(item.key, item.member)));
|
|
431
|
-
}
|
|
394
|
+
}
|
|
395
|
+
catch (error) {
|
|
432
396
|
Logger.error({ err: error }, "Redis sismemberBatch 错误");
|
|
433
397
|
return items.map(() => false);
|
|
434
398
|
}
|
|
435
399
|
}
|
|
436
|
-
|
|
437
400
|
/**
|
|
438
401
|
* 删除键
|
|
439
402
|
* @param key - 键名
|
|
440
403
|
* @returns 删除的键数量
|
|
441
404
|
*/
|
|
442
|
-
async del(key
|
|
405
|
+
async del(key) {
|
|
443
406
|
try {
|
|
444
407
|
const pkey = `${this.prefix}${key}`;
|
|
445
|
-
|
|
446
408
|
const startTime = Date.now();
|
|
447
409
|
const res = await this.client.del(pkey);
|
|
448
410
|
const duration = Date.now() - startTime;
|
|
449
411
|
this.logSlow("DEL", pkey, duration);
|
|
450
412
|
return res;
|
|
451
|
-
}
|
|
413
|
+
}
|
|
414
|
+
catch (error) {
|
|
452
415
|
Logger.error({ err: error }, "Redis del 错误");
|
|
453
416
|
return 0;
|
|
454
417
|
}
|
|
455
418
|
}
|
|
456
|
-
|
|
457
419
|
/**
|
|
458
420
|
* 批量删除键(利用 Bun Redis 自动管道优化)
|
|
459
421
|
* @param keys - 键名数组
|
|
460
422
|
* @returns 成功删除的键数量
|
|
461
423
|
*/
|
|
462
|
-
async delBatch(keys
|
|
424
|
+
async delBatch(keys) {
|
|
463
425
|
if (keys.length === 0) {
|
|
464
426
|
return 0;
|
|
465
427
|
}
|
|
466
|
-
|
|
467
428
|
try {
|
|
468
|
-
const results = await Promise.all(
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
})
|
|
473
|
-
);
|
|
429
|
+
const results = await Promise.all(keys.map((key) => {
|
|
430
|
+
const pkey = `${this.prefix}${key}`;
|
|
431
|
+
return this.client.del(pkey);
|
|
432
|
+
}));
|
|
474
433
|
return results.reduce((sum, count) => sum + count, 0);
|
|
475
|
-
}
|
|
434
|
+
}
|
|
435
|
+
catch (error) {
|
|
476
436
|
Logger.error({ err: error }, "Redis delBatch 错误");
|
|
477
437
|
return 0;
|
|
478
438
|
}
|
|
479
439
|
}
|
|
480
|
-
|
|
481
440
|
/**
|
|
482
441
|
* 批量设置对象(利用 Bun Redis 自动管道优化)
|
|
483
442
|
* @param items - 键值对数组 [{ key, value, ttl? }]
|
|
484
443
|
* @returns 成功设置的数量
|
|
485
444
|
*/
|
|
486
|
-
async setBatch
|
|
445
|
+
async setBatch(items) {
|
|
487
446
|
if (items.length === 0) {
|
|
488
447
|
return 0;
|
|
489
448
|
}
|
|
490
|
-
|
|
491
449
|
try {
|
|
492
450
|
const results = await Promise.all(items.map((item) => this.setObject(item.key, item.value, item.ttl ?? null)));
|
|
493
451
|
return results.filter((r) => r !== null).length;
|
|
494
|
-
}
|
|
452
|
+
}
|
|
453
|
+
catch (error) {
|
|
495
454
|
Logger.error({ err: error }, "Redis setBatch 错误");
|
|
496
455
|
return 0;
|
|
497
456
|
}
|
|
498
457
|
}
|
|
499
|
-
|
|
500
458
|
/**
|
|
501
459
|
* 批量获取对象(利用 Bun Redis 自动管道优化)
|
|
502
460
|
* @param keys - 键名数组
|
|
503
461
|
* @returns 对象数组(不存在的键返回 null)
|
|
504
462
|
*/
|
|
505
|
-
async getBatch
|
|
463
|
+
async getBatch(keys) {
|
|
506
464
|
if (keys.length === 0) {
|
|
507
465
|
return [];
|
|
508
466
|
}
|
|
509
|
-
|
|
510
467
|
try {
|
|
511
|
-
const results = await Promise.all(keys.map((key) => this.getObject
|
|
468
|
+
const results = await Promise.all(keys.map((key) => this.getObject(key)));
|
|
512
469
|
return results;
|
|
513
|
-
}
|
|
470
|
+
}
|
|
471
|
+
catch (error) {
|
|
514
472
|
Logger.error({ err: error }, "Redis getBatch 错误");
|
|
515
473
|
return keys.map(() => null);
|
|
516
474
|
}
|
|
517
475
|
}
|
|
518
|
-
|
|
519
476
|
/**
|
|
520
477
|
* 批量检查键是否存在(利用 Bun Redis 自动管道优化)
|
|
521
478
|
* @param keys - 键名数组
|
|
522
479
|
* @returns 布尔数组(true 表示存在,false 表示不存在)
|
|
523
480
|
*/
|
|
524
|
-
async existsBatch(keys
|
|
481
|
+
async existsBatch(keys) {
|
|
525
482
|
if (keys.length === 0) {
|
|
526
483
|
return [];
|
|
527
484
|
}
|
|
528
|
-
|
|
529
485
|
try {
|
|
530
486
|
return await Promise.all(keys.map((key) => this.exists(key)));
|
|
531
|
-
}
|
|
487
|
+
}
|
|
488
|
+
catch (error) {
|
|
532
489
|
Logger.error({ err: error }, "Redis existsBatch 错误");
|
|
533
490
|
return keys.map(() => false);
|
|
534
491
|
}
|
|
535
492
|
}
|
|
536
|
-
|
|
537
493
|
/**
|
|
538
494
|
* 批量设置过期时间(利用 Bun Redis 自动管道优化)
|
|
539
495
|
* @param items - 键名和过期时间数组 [{ key, seconds }]
|
|
540
496
|
* @returns 成功设置的数量
|
|
541
497
|
*/
|
|
542
|
-
async expireBatch(items
|
|
498
|
+
async expireBatch(items) {
|
|
543
499
|
if (items.length === 0) {
|
|
544
500
|
return 0;
|
|
545
501
|
}
|
|
546
|
-
|
|
547
502
|
try {
|
|
548
503
|
const results = await Promise.all(items.map((item) => this.expire(item.key, item.seconds)));
|
|
549
504
|
return results.filter((r) => r > 0).length;
|
|
550
|
-
}
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
551
507
|
Logger.error({ err: error }, "Redis expireBatch 错误");
|
|
552
508
|
return 0;
|
|
553
509
|
}
|
|
554
510
|
}
|
|
555
|
-
|
|
556
511
|
/**
|
|
557
512
|
* 测试 Redis 连接
|
|
558
513
|
* @returns ping 响应结果
|
|
559
514
|
*/
|
|
560
|
-
async ping()
|
|
515
|
+
async ping() {
|
|
561
516
|
try {
|
|
562
517
|
const startTime = Date.now();
|
|
563
518
|
const res = await this.client.ping();
|
|
564
519
|
const duration = Date.now() - startTime;
|
|
565
520
|
this.logSlow("PING", "(no-key)", duration);
|
|
566
521
|
return res;
|
|
567
|
-
}
|
|
522
|
+
}
|
|
523
|
+
catch (error) {
|
|
568
524
|
Logger.error({ err: error }, "Redis ping 错误");
|
|
569
525
|
throw error;
|
|
570
526
|
}
|