befly 3.74.3 → 3.75.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/apis/dashboard/systemResources.js +3 -1
- package/apis/dict/_dict.js +1 -1
- package/apis/role/_role.js +2 -2
- package/apis/tongJi/dailyStats.js +2 -2
- package/apis/tongJi/dailyStatsDistribution.js +3 -3
- package/apis/tongJi/errorList.js +2 -2
- package/apis/tongJi/errorStats.js +6 -6
- package/checks/api.js +14 -8
- package/checks/config.js +4 -3
- package/checks/items.js +65 -0
- package/checks/menu.js +4 -3
- package/checks/table.js +7 -7
- package/configs/beflyConfig.json +5 -10
- package/configs/constConfig.js +44 -3
- package/hooks/auth.js +3 -2
- package/hooks/parser.js +15 -4
- package/hooks/permission.js +3 -2
- package/hooks/rateLimit.js +16 -3
- package/hooks/validator.js +2 -1
- package/index.js +72 -28
- package/lib/cacheHelper.js +83 -229
- package/lib/connect.js +3 -13
- package/lib/dbHelper.js +57 -142
- package/lib/dbParse.js +65 -248
- package/lib/dbUtil.js +19 -63
- package/lib/logger.js +45 -22
- package/lib/redisHelper.js +186 -420
- package/lib/smtpText.js +7 -18
- package/lib/sqlBuilder.js +22 -51
- package/lib/xmlParse.js +15 -59
- package/package.json +1 -1
- package/plugins/cache.js +2 -3
- package/plugins/config.js +3 -1
- package/plugins/cron.js +2 -2
- package/plugins/email.js +3 -1
- package/plugins/logger.js +2 -2
- package/plugins/mysql.js +5 -10
- package/plugins/redis.js +4 -11
- package/plugins/tool.js +3 -3
- package/plugins/xmlParse.js +3 -1
- package/router/api.js +2 -6
- package/router/static.js +9 -10
- package/schemas/config.js +4 -4
- package/scripts/syncDb/context.js +4 -7
- package/scripts/syncDb/diff.js +2 -1
- package/scripts/syncDb/index.js +2 -6
- package/sync/api.js +7 -8
- package/sync/cache.js +3 -1
- package/sync/dev.js +28 -65
- package/sync/menu.js +5 -6
- package/sync/syncUtil.js +25 -0
- package/utils/calcPerfTime.js +2 -3
- package/utils/crypto.js +0 -40
- package/utils/deepMerge.js +2 -6
- package/utils/error.js +64 -0
- package/utils/fieldClear.js +13 -56
- package/utils/importDefault.js +11 -12
- package/utils/is.js +3 -180
- package/utils/loggerUtils.js +3 -1
- package/utils/response.js +12 -8
- package/utils/scanFiles.js +2 -53
- package/utils/scanSources.js +9 -0
- package/utils/util.js +25 -222
- package/checks/hook.js +0 -39
- package/checks/plugin.js +0 -39
- package/utils/processInfo.js +0 -39
package/lib/cacheHelper.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 缓存助手 - JavaScript 版本
|
|
3
2
|
* 负责在服务器启动时缓存接口、菜单和角色权限到 Redis
|
|
4
3
|
*/
|
|
5
4
|
|
|
5
|
+
import { BEFLY_API_TABLE, BEFLY_MENU_TABLE, BEFLY_ROLE_TABLE } from "../configs/constConfig.js";
|
|
6
|
+
import { createError } from "../utils/error.js";
|
|
6
7
|
import { isNonEmptyString, isNullable, isString } from "../utils/is.js";
|
|
7
8
|
import { Logger } from "./logger.js";
|
|
8
9
|
|
|
@@ -105,161 +106,105 @@ export class CacheHelper {
|
|
|
105
106
|
}
|
|
106
107
|
|
|
107
108
|
/**
|
|
108
|
-
*
|
|
109
|
+
* 缓存某类全部数据到 Redis(从数据库读取)
|
|
110
|
+
* @param kind - 数据类别(apis/menus),决定 Redis key 与日志文案
|
|
111
|
+
* @param table - 数据库表名
|
|
109
112
|
*/
|
|
110
|
-
async
|
|
113
|
+
async cacheAllItems(kind, table) {
|
|
111
114
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
table: "beflyApi"
|
|
115
|
+
const items = await this.mysql.getAll({
|
|
116
|
+
table: table
|
|
115
117
|
});
|
|
116
118
|
|
|
117
|
-
|
|
118
|
-
const result = await this.redis.setObject("apis:all", apiList.data.lists);
|
|
119
|
+
const result = await this.redis.setObject(`${kind}:all`, items.data.lists);
|
|
119
120
|
|
|
120
121
|
if (result === null) {
|
|
121
|
-
Logger.warn(
|
|
122
|
+
Logger.warn(`⚠️ ${kind} 缓存失败`, {
|
|
122
123
|
subsystem: "cache",
|
|
123
|
-
operation: "
|
|
124
|
+
operation: "cacheAllItems"
|
|
124
125
|
});
|
|
125
126
|
}
|
|
126
127
|
} catch (error) {
|
|
127
|
-
|
|
128
|
-
throw new Error("接口缓存异常", {
|
|
129
|
-
cause: error,
|
|
130
|
-
code: "runtime",
|
|
131
|
-
subsystem: "cache",
|
|
132
|
-
operation: "cacheApis"
|
|
133
|
-
});
|
|
128
|
+
throw createError(`${kind} 缓存异常`, { cause: error, code: "runtime", subsystem: "cache", operation: "cacheAllItems" });
|
|
134
129
|
}
|
|
135
130
|
}
|
|
136
131
|
|
|
132
|
+
/**
|
|
133
|
+
* 缓存所有接口到 Redis
|
|
134
|
+
*/
|
|
135
|
+
async cacheApis() {
|
|
136
|
+
return this.cacheAllItems("apis", BEFLY_API_TABLE);
|
|
137
|
+
}
|
|
138
|
+
|
|
137
139
|
/**
|
|
138
140
|
* 缓存所有菜单到 Redis(从数据库读取)
|
|
139
141
|
*/
|
|
140
142
|
async cacheMenus() {
|
|
141
|
-
|
|
142
|
-
// 从数据库查询所有菜单
|
|
143
|
-
const menus = await this.mysql.getAll({
|
|
144
|
-
table: "beflyMenu"
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
// 缓存到 Redis
|
|
148
|
-
const result = await this.redis.setObject("menus:all", menus.data.lists);
|
|
149
|
-
|
|
150
|
-
if (result === null) {
|
|
151
|
-
Logger.warn("⚠️ 菜单缓存失败", {
|
|
152
|
-
subsystem: "cache",
|
|
153
|
-
operation: "cacheMenus"
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
} catch (error) {
|
|
157
|
-
Logger.error("⚠️ 菜单缓存异常", error);
|
|
158
|
-
throw new Error("菜单缓存异常", {
|
|
159
|
-
cause: error,
|
|
160
|
-
code: "runtime",
|
|
161
|
-
subsystem: "cache",
|
|
162
|
-
operation: "cacheMenus"
|
|
163
|
-
});
|
|
164
|
-
}
|
|
143
|
+
return this.cacheAllItems("menus", BEFLY_MENU_TABLE);
|
|
165
144
|
}
|
|
166
145
|
|
|
167
146
|
/**
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
* -
|
|
147
|
+
* 缓存所有角色的某类权限到 Redis
|
|
148
|
+
* 全量重建:清理所有角色权限缓存并重建(DEL + SADD)
|
|
149
|
+
* @param kind - 权限类别(apis/menus),同时是 beflyRole 表字段名
|
|
171
150
|
*/
|
|
172
|
-
async
|
|
151
|
+
async cacheRoleItems(kind) {
|
|
173
152
|
try {
|
|
174
|
-
// 查询所有角色(仅取必要字段)
|
|
175
153
|
const roles = await this.mysql.getAll({
|
|
176
|
-
table:
|
|
177
|
-
fields: ["code",
|
|
154
|
+
table: BEFLY_ROLE_TABLE,
|
|
155
|
+
fields: ["code", kind]
|
|
178
156
|
});
|
|
179
157
|
|
|
180
|
-
const
|
|
158
|
+
const roleValuesMap = new Map();
|
|
181
159
|
|
|
182
160
|
for (const role of roles.data.lists) {
|
|
183
161
|
if (!role?.code) continue;
|
|
184
|
-
|
|
162
|
+
roleValuesMap.set(role.code, role[kind]);
|
|
185
163
|
}
|
|
186
164
|
|
|
187
|
-
await this.rebuildRoleCache(
|
|
165
|
+
await this.rebuildRoleCache(kind, roleValuesMap);
|
|
188
166
|
} catch (error) {
|
|
189
|
-
|
|
190
|
-
throw new Error("⚠️ 角色权限缓存异常(将阻断启动)", {
|
|
191
|
-
cause: error,
|
|
192
|
-
code: "runtime",
|
|
193
|
-
subsystem: "cache",
|
|
194
|
-
operation: "cacheRoleApis"
|
|
195
|
-
});
|
|
167
|
+
throw createError(`⚠️ 角色${kind}权限缓存异常(将阻断启动)`, { cause: error, code: "runtime", subsystem: "cache", operation: "cacheRoleItems" });
|
|
196
168
|
}
|
|
197
169
|
}
|
|
198
170
|
|
|
171
|
+
/**
|
|
172
|
+
* 缓存所有角色的接口权限到 Redis
|
|
173
|
+
*/
|
|
174
|
+
async cacheRoleApis() {
|
|
175
|
+
return this.cacheRoleItems("apis");
|
|
176
|
+
}
|
|
177
|
+
|
|
199
178
|
/**
|
|
200
179
|
* 缓存所有角色的菜单权限到 Redis
|
|
201
|
-
* 全量重建:清理所有角色菜单权限缓存并重建
|
|
202
|
-
* - 每个角色一个 Set,直接覆盖更新(DEL + SADD)
|
|
203
180
|
*/
|
|
204
181
|
async cacheRoleMenus() {
|
|
205
|
-
|
|
206
|
-
// 查询所有角色(仅取必要字段)
|
|
207
|
-
const roles = await this.mysql.getAll({
|
|
208
|
-
table: "beflyRole",
|
|
209
|
-
fields: ["code", "menus"]
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
const roleMenuPathsMap = new Map();
|
|
213
|
-
|
|
214
|
-
for (const role of roles.data.lists) {
|
|
215
|
-
if (!role?.code) continue;
|
|
216
|
-
roleMenuPathsMap.set(role.code, role.menus);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
await this.rebuildRoleCache("menus", roleMenuPathsMap);
|
|
220
|
-
} catch (error) {
|
|
221
|
-
Logger.error("⚠️ 角色菜单权限缓存异常(将阻断启动)", error);
|
|
222
|
-
throw new Error("⚠️ 角色菜单权限缓存异常(将阻断启动)", {
|
|
223
|
-
cause: error,
|
|
224
|
-
code: "runtime",
|
|
225
|
-
subsystem: "cache",
|
|
226
|
-
operation: "cacheRoleMenus"
|
|
227
|
-
});
|
|
228
|
-
}
|
|
182
|
+
return this.cacheRoleItems("menus");
|
|
229
183
|
}
|
|
230
184
|
|
|
231
185
|
/**
|
|
232
|
-
*
|
|
233
|
-
* -
|
|
234
|
-
* -
|
|
186
|
+
* 增量刷新单个角色的某类权限缓存
|
|
187
|
+
* - paths 为空数组:仅清理缓存(防止残留)
|
|
188
|
+
* - paths 非空:使用最小查询,DEL 后 SADD
|
|
189
|
+
* @param kind - 权限类别(apis/menus)
|
|
235
190
|
*/
|
|
236
|
-
async
|
|
191
|
+
async refreshRoleItems(kind, roleCode, paths) {
|
|
237
192
|
if (!isNonEmptyString(roleCode)) {
|
|
238
|
-
throw
|
|
239
|
-
cause: null,
|
|
240
|
-
code: "validation",
|
|
241
|
-
subsystem: "cache",
|
|
242
|
-
operation: "refreshRoleApis"
|
|
243
|
-
});
|
|
193
|
+
throw createError("roleCode 参数不合法", { code: "validation", subsystem: "cache", operation: "refreshRoleItems" });
|
|
244
194
|
}
|
|
245
|
-
if (!Array.isArray(
|
|
246
|
-
throw
|
|
247
|
-
cause: null,
|
|
248
|
-
code: "validation",
|
|
249
|
-
subsystem: "cache",
|
|
250
|
-
operation: "refreshRoleApis"
|
|
251
|
-
});
|
|
195
|
+
if (!Array.isArray(paths)) {
|
|
196
|
+
throw createError("paths 参数不合法", { code: "validation", subsystem: "cache", operation: "refreshRoleItems" });
|
|
252
197
|
}
|
|
253
198
|
|
|
254
|
-
const roleKey = await this.getRoleCacheReadKey(
|
|
199
|
+
const roleKey = await this.getRoleCacheReadKey(kind, roleCode);
|
|
255
200
|
|
|
256
201
|
// 空数组短路:保证清理残留
|
|
257
|
-
if (
|
|
202
|
+
if (paths.length === 0) {
|
|
258
203
|
await this.redis.del(roleKey);
|
|
259
204
|
return;
|
|
260
205
|
}
|
|
261
206
|
|
|
262
|
-
const members = Array.from(new Set(
|
|
207
|
+
const members = Array.from(new Set(paths));
|
|
263
208
|
|
|
264
209
|
await this.redis.del(roleKey);
|
|
265
210
|
if (members.length > 0) {
|
|
@@ -268,59 +213,21 @@ export class CacheHelper {
|
|
|
268
213
|
}
|
|
269
214
|
|
|
270
215
|
/**
|
|
271
|
-
*
|
|
272
|
-
* -
|
|
273
|
-
* -
|
|
216
|
+
* 增量刷新单个角色的接口权限缓存
|
|
217
|
+
* - apiPaths 为空数组:仅清理缓存(防止残留)
|
|
218
|
+
* - apiPaths 非空:使用 $in 最小查询,DEL 后 SADD
|
|
274
219
|
*/
|
|
275
|
-
async
|
|
276
|
-
|
|
277
|
-
throw new Error("roleCode 参数不合法", {
|
|
278
|
-
cause: null,
|
|
279
|
-
code: "validation",
|
|
280
|
-
subsystem: "cache",
|
|
281
|
-
operation: "refreshRoleMenus"
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
if (!Array.isArray(menuPaths)) {
|
|
285
|
-
throw new Error("menuPaths 参数不合法", {
|
|
286
|
-
cause: null,
|
|
287
|
-
code: "validation",
|
|
288
|
-
subsystem: "cache",
|
|
289
|
-
operation: "refreshRoleMenus"
|
|
290
|
-
});
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
const roleKey = await this.getRoleCacheReadKey("menus", roleCode);
|
|
294
|
-
|
|
295
|
-
// 空数组短路:保证清理残留
|
|
296
|
-
if (menuPaths.length === 0) {
|
|
297
|
-
await this.redis.del(roleKey);
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
const members = Array.from(new Set(menuPaths));
|
|
302
|
-
|
|
303
|
-
await this.redis.del(roleKey);
|
|
304
|
-
if (members.length > 0) {
|
|
305
|
-
await this.redis.sadd(roleKey, members);
|
|
306
|
-
}
|
|
220
|
+
async refreshRoleApis(roleCode, apiPaths) {
|
|
221
|
+
return this.refreshRoleItems("apis", roleCode, apiPaths);
|
|
307
222
|
}
|
|
308
223
|
|
|
309
224
|
/**
|
|
310
|
-
*
|
|
225
|
+
* 增量刷新单个角色的菜单权限缓存
|
|
226
|
+
* - menuPaths 为空数组:仅清理缓存(防止残留)
|
|
227
|
+
* - menuPaths 非空:DEL 后 SADD
|
|
311
228
|
*/
|
|
312
|
-
async
|
|
313
|
-
|
|
314
|
-
await this.cacheApis();
|
|
315
|
-
|
|
316
|
-
// 2. 缓存菜单
|
|
317
|
-
await this.cacheMenus();
|
|
318
|
-
|
|
319
|
-
// 3. 缓存角色权限
|
|
320
|
-
await this.cacheRoleApis();
|
|
321
|
-
|
|
322
|
-
// 4. 缓存角色菜单权限
|
|
323
|
-
await this.cacheRoleMenus();
|
|
229
|
+
async refreshRoleMenus(roleCode, menuPaths) {
|
|
230
|
+
return this.refreshRoleItems("menus", roleCode, menuPaths);
|
|
324
231
|
}
|
|
325
232
|
|
|
326
233
|
/**
|
|
@@ -332,13 +239,7 @@ export class CacheHelper {
|
|
|
332
239
|
const apis = await this.redis.getObject("apis:all");
|
|
333
240
|
return apis || [];
|
|
334
241
|
} catch (error) {
|
|
335
|
-
|
|
336
|
-
throw new Error("获取接口缓存失败", {
|
|
337
|
-
cause: error,
|
|
338
|
-
code: "runtime",
|
|
339
|
-
subsystem: "cache",
|
|
340
|
-
operation: "getApis"
|
|
341
|
-
});
|
|
242
|
+
throw createError("获取接口缓存失败", { cause: error, code: "runtime", subsystem: "cache", operation: "getApis" });
|
|
342
243
|
}
|
|
343
244
|
}
|
|
344
245
|
|
|
@@ -351,13 +252,7 @@ export class CacheHelper {
|
|
|
351
252
|
const menus = await this.redis.getObject("menus:all");
|
|
352
253
|
return menus || [];
|
|
353
254
|
} catch (error) {
|
|
354
|
-
|
|
355
|
-
throw new Error("获取菜单缓存失败", {
|
|
356
|
-
cause: error,
|
|
357
|
-
code: "runtime",
|
|
358
|
-
subsystem: "cache",
|
|
359
|
-
operation: "getMenus"
|
|
360
|
-
});
|
|
255
|
+
throw createError("获取菜单缓存失败", { cause: error, code: "runtime", subsystem: "cache", operation: "getMenus" });
|
|
361
256
|
}
|
|
362
257
|
}
|
|
363
258
|
|
|
@@ -372,14 +267,7 @@ export class CacheHelper {
|
|
|
372
267
|
const permissions = await this.redis.smembers(roleKey);
|
|
373
268
|
return permissions || [];
|
|
374
269
|
} catch (error) {
|
|
375
|
-
|
|
376
|
-
throw new Error("获取角色权限缓存失败", {
|
|
377
|
-
cause: error,
|
|
378
|
-
code: "runtime",
|
|
379
|
-
subsystem: "cache",
|
|
380
|
-
operation: "getRoleApis",
|
|
381
|
-
roleCode: roleCode
|
|
382
|
-
});
|
|
270
|
+
throw createError("获取角色权限缓存失败", { cause: error, code: "runtime", subsystem: "cache", operation: "getRoleApis", roleCode: roleCode });
|
|
383
271
|
}
|
|
384
272
|
}
|
|
385
273
|
|
|
@@ -394,14 +282,7 @@ export class CacheHelper {
|
|
|
394
282
|
const permissions = await this.redis.smembers(roleKey);
|
|
395
283
|
return permissions || [];
|
|
396
284
|
} catch (error) {
|
|
397
|
-
|
|
398
|
-
throw new Error("获取角色菜单权限缓存失败", {
|
|
399
|
-
cause: error,
|
|
400
|
-
code: "runtime",
|
|
401
|
-
subsystem: "cache",
|
|
402
|
-
operation: "getRoleMenus",
|
|
403
|
-
roleCode: roleCode
|
|
404
|
-
});
|
|
285
|
+
throw createError("获取角色菜单权限缓存失败", { cause: error, code: "runtime", subsystem: "cache", operation: "getRoleMenus", roleCode: roleCode });
|
|
405
286
|
}
|
|
406
287
|
}
|
|
407
288
|
|
|
@@ -418,14 +299,7 @@ export class CacheHelper {
|
|
|
418
299
|
const roleKey = await this.getRoleCacheReadKey("apis", roleCode);
|
|
419
300
|
return await this.redis.sismember(roleKey, value);
|
|
420
301
|
} catch (error) {
|
|
421
|
-
|
|
422
|
-
throw new Error("检查角色权限失败", {
|
|
423
|
-
cause: error,
|
|
424
|
-
code: "runtime",
|
|
425
|
-
subsystem: "cache",
|
|
426
|
-
operation: "checkRoleApis",
|
|
427
|
-
roleCode: roleCode
|
|
428
|
-
});
|
|
302
|
+
throw createError("检查角色权限失败", { cause: error, code: "runtime", subsystem: "cache", operation: "checkRoleApis", roleCode: roleCode });
|
|
429
303
|
}
|
|
430
304
|
}
|
|
431
305
|
|
|
@@ -442,66 +316,46 @@ export class CacheHelper {
|
|
|
442
316
|
const roleKey = await this.getRoleCacheReadKey("menus", roleCode);
|
|
443
317
|
return await this.redis.sismember(roleKey, value);
|
|
444
318
|
} catch (error) {
|
|
445
|
-
|
|
446
|
-
throw new Error("检查角色菜单权限失败", {
|
|
447
|
-
cause: error,
|
|
448
|
-
code: "runtime",
|
|
449
|
-
subsystem: "cache",
|
|
450
|
-
operation: "checkRoleMenus",
|
|
451
|
-
roleCode: roleCode
|
|
452
|
-
});
|
|
319
|
+
throw createError("检查角色菜单权限失败", { cause: error, code: "runtime", subsystem: "cache", operation: "checkRoleMenus", roleCode: roleCode });
|
|
453
320
|
}
|
|
454
321
|
}
|
|
455
322
|
|
|
456
323
|
/**
|
|
457
|
-
*
|
|
324
|
+
* 删除角色的某类权限缓存
|
|
325
|
+
* @param kind - 权限类别(apis/menus)
|
|
458
326
|
* @param roleCode - 角色代码
|
|
459
327
|
* @returns 是否删除成功
|
|
460
328
|
*/
|
|
461
|
-
async
|
|
329
|
+
async deleteRoleItems(kind, roleCode) {
|
|
462
330
|
try {
|
|
463
|
-
const roleReadKey = await this.getRoleCacheReadKey(
|
|
464
|
-
|
|
331
|
+
const roleReadKey = await this.getRoleCacheReadKey(kind, roleCode);
|
|
332
|
+
// 同时清理无版本旧 key(permission hook 的兜底读取路径)
|
|
333
|
+
const result = await this.redis.delBatch([`role:${kind}:${roleCode}`, roleReadKey]);
|
|
465
334
|
if (result > 0) {
|
|
466
|
-
Logger.info(`✅ 已删除角色 ${roleCode}
|
|
335
|
+
Logger.info(`✅ 已删除角色 ${roleCode} 的${kind}权限缓存`);
|
|
467
336
|
return true;
|
|
468
337
|
}
|
|
469
338
|
return false;
|
|
470
339
|
} catch (error) {
|
|
471
|
-
|
|
472
|
-
throw new Error("删除角色权限缓存失败", {
|
|
473
|
-
cause: error,
|
|
474
|
-
code: "runtime",
|
|
475
|
-
subsystem: "cache",
|
|
476
|
-
operation: "deleteRoleApis",
|
|
477
|
-
roleCode: roleCode
|
|
478
|
-
});
|
|
340
|
+
throw createError("删除角色权限缓存失败", { cause: error, code: "runtime", subsystem: "cache", operation: "deleteRoleItems", roleCode: roleCode });
|
|
479
341
|
}
|
|
480
342
|
}
|
|
481
343
|
|
|
344
|
+
/**
|
|
345
|
+
* 删除角色的接口权限缓存
|
|
346
|
+
* @param roleCode - 角色代码
|
|
347
|
+
* @returns 是否删除成功
|
|
348
|
+
*/
|
|
349
|
+
async deleteRoleApis(roleCode) {
|
|
350
|
+
return this.deleteRoleItems("apis", roleCode);
|
|
351
|
+
}
|
|
352
|
+
|
|
482
353
|
/**
|
|
483
354
|
* 删除角色的菜单权限缓存
|
|
484
355
|
* @param roleCode - 角色代码
|
|
485
356
|
* @returns 是否删除成功
|
|
486
357
|
*/
|
|
487
358
|
async deleteRoleMenus(roleCode) {
|
|
488
|
-
|
|
489
|
-
const roleReadKey = await this.getRoleCacheReadKey("menus", roleCode);
|
|
490
|
-
const result = await this.redis.delBatch([`role:menus:${roleCode}`, roleReadKey]);
|
|
491
|
-
if (result > 0) {
|
|
492
|
-
Logger.info(`✅ 已删除角色 ${roleCode} 的菜单权限缓存`);
|
|
493
|
-
return true;
|
|
494
|
-
}
|
|
495
|
-
return false;
|
|
496
|
-
} catch (error) {
|
|
497
|
-
Logger.error("删除角色菜单权限缓存失败", error, { roleCode: roleCode });
|
|
498
|
-
throw new Error("删除角色菜单权限缓存失败", {
|
|
499
|
-
cause: error,
|
|
500
|
-
code: "runtime",
|
|
501
|
-
subsystem: "cache",
|
|
502
|
-
operation: "deleteRoleMenus",
|
|
503
|
-
roleCode: roleCode
|
|
504
|
-
});
|
|
505
|
-
}
|
|
359
|
+
return this.deleteRoleItems("menus", roleCode);
|
|
506
360
|
}
|
|
507
361
|
}
|
package/lib/connect.js
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 连接管理器 - JavaScript 版本
|
|
3
2
|
* 负责管理数据库和 Redis 连接
|
|
4
3
|
*/
|
|
5
4
|
|
|
6
5
|
import { RedisClient, SQL } from "bun";
|
|
7
6
|
|
|
7
|
+
import { createError } from "../utils/error.js";
|
|
8
|
+
import { getRunMode } from "../utils/util.js";
|
|
8
9
|
import { Logger } from "./logger.js";
|
|
9
10
|
|
|
10
|
-
function getRunMode() {
|
|
11
|
-
return Bun.env.RUN_MODE || "unknown";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
11
|
function buildRedisUrl(config) {
|
|
15
12
|
if (config.username) {
|
|
16
13
|
const encodedUser = encodeURIComponent(config.username);
|
|
@@ -52,14 +49,7 @@ export class Connect {
|
|
|
52
49
|
static async handleConnectError(clientKey, label, subsystem, hostname, error) {
|
|
53
50
|
await this[clientKey]?.close();
|
|
54
51
|
this[clientKey] = null;
|
|
55
|
-
|
|
56
|
-
throw new Error(`${label} 连接失败 (${hostname})`, {
|
|
57
|
-
cause: error,
|
|
58
|
-
code: "runtime",
|
|
59
|
-
subsystem: subsystem,
|
|
60
|
-
operation: "connect",
|
|
61
|
-
runMode: getRunMode()
|
|
62
|
-
});
|
|
52
|
+
throw createError(`${label} 连接失败 (${hostname})`, { cause: error, code: "runtime", subsystem: subsystem, operation: "connect", runMode: getRunMode() });
|
|
63
53
|
}
|
|
64
54
|
|
|
65
55
|
/**
|