befly 3.16.5 → 3.16.7
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/dist/befly.js +279 -61
- package/dist/befly.min.js +16 -16
- package/dist/index.js +57 -16
- package/dist/lib/cacheHelper.d.ts +33 -0
- package/dist/lib/cacheHelper.js +185 -0
- package/dist/lib/cacheKeys.d.ts +6 -0
- package/dist/lib/cacheKeys.js +8 -0
- package/dist/lib/redisHelper.d.ts +8 -0
- package/dist/lib/redisHelper.js +60 -1
- package/dist/sync/syncCache.js +2 -0
- package/dist/types/cache.d.ts +27 -0
- package/dist/types/redis.d.ts +10 -0
- package/package.json +3 -3
package/dist/befly.js
CHANGED
|
@@ -2499,7 +2499,7 @@ var require_bn = __commonJS((exports, module) => {
|
|
|
2499
2499
|
}
|
|
2500
2500
|
assert(false, "Base should be between 2 and 36");
|
|
2501
2501
|
};
|
|
2502
|
-
BN.prototype.toNumber = function
|
|
2502
|
+
BN.prototype.toNumber = function toNumber2() {
|
|
2503
2503
|
var ret = this.words[0];
|
|
2504
2504
|
if (this.length === 2) {
|
|
2505
2505
|
ret += this.words[1] * 67108864;
|
|
@@ -2918,7 +2918,7 @@ var require_bn = __commonJS((exports, module) => {
|
|
|
2918
2918
|
}
|
|
2919
2919
|
return out.strip();
|
|
2920
2920
|
}
|
|
2921
|
-
var comb10MulTo = function
|
|
2921
|
+
var comb10MulTo = function comb10MulTo2(self, num, out) {
|
|
2922
2922
|
var a = self.words;
|
|
2923
2923
|
var b = num.words;
|
|
2924
2924
|
var o = out.words;
|
|
@@ -4603,20 +4603,20 @@ var require_bn = __commonJS((exports, module) => {
|
|
|
4603
4603
|
BN._prime = function prime(name) {
|
|
4604
4604
|
if (primes[name])
|
|
4605
4605
|
return primes[name];
|
|
4606
|
-
var
|
|
4606
|
+
var prime2;
|
|
4607
4607
|
if (name === "k256") {
|
|
4608
|
-
|
|
4608
|
+
prime2 = new K256;
|
|
4609
4609
|
} else if (name === "p224") {
|
|
4610
|
-
|
|
4610
|
+
prime2 = new P224;
|
|
4611
4611
|
} else if (name === "p192") {
|
|
4612
|
-
|
|
4612
|
+
prime2 = new P192;
|
|
4613
4613
|
} else if (name === "p25519") {
|
|
4614
|
-
|
|
4614
|
+
prime2 = new P25519;
|
|
4615
4615
|
} else {
|
|
4616
4616
|
throw new Error("Unknown prime " + name);
|
|
4617
4617
|
}
|
|
4618
|
-
primes[name] =
|
|
4619
|
-
return
|
|
4618
|
+
primes[name] = prime2;
|
|
4619
|
+
return prime2;
|
|
4620
4620
|
};
|
|
4621
4621
|
function Red(m) {
|
|
4622
4622
|
if (typeof m === "string") {
|
|
@@ -5161,7 +5161,7 @@ var require_buffer = __commonJS((exports) => {
|
|
|
5161
5161
|
const isCompatible = typeof data === "object" && data.constructor.name === "EncoderBuffer" && typeof data.length === "number" && typeof data.join === "function";
|
|
5162
5162
|
return isCompatible;
|
|
5163
5163
|
};
|
|
5164
|
-
EncoderBuffer.prototype.join = function
|
|
5164
|
+
EncoderBuffer.prototype.join = function join3(out, offset) {
|
|
5165
5165
|
if (!out)
|
|
5166
5166
|
out = Buffer2.alloc(this.length);
|
|
5167
5167
|
if (!offset)
|
|
@@ -9833,6 +9833,7 @@ async function syncCache(ctx) {
|
|
|
9833
9833
|
await ctx.cache.cacheApis();
|
|
9834
9834
|
await ctx.cache.cacheMenus();
|
|
9835
9835
|
await ctx.cache.rebuildRoleApiPermissions();
|
|
9836
|
+
await ctx.cache.rebuildRoleMenuPermissions();
|
|
9836
9837
|
}
|
|
9837
9838
|
|
|
9838
9839
|
// lib/cipher.ts
|
|
@@ -11482,32 +11483,6 @@ var calcPerfTime = (startTime, endTime = Bun.nanoseconds()) => {
|
|
|
11482
11483
|
}
|
|
11483
11484
|
};
|
|
11484
11485
|
|
|
11485
|
-
// utils/processInfo.ts
|
|
11486
|
-
function getProcessRole(env) {
|
|
11487
|
-
const runtimeEnv = env || {};
|
|
11488
|
-
const bunWorkerId = runtimeEnv["BUN_WORKER_ID"];
|
|
11489
|
-
const pm2InstanceId = runtimeEnv["PM2_INSTANCE_ID"];
|
|
11490
|
-
if (bunWorkerId !== undefined) {
|
|
11491
|
-
return {
|
|
11492
|
-
role: bunWorkerId === "" ? "primary" : "worker",
|
|
11493
|
-
instanceId: bunWorkerId || "0",
|
|
11494
|
-
env: "bun-cluster"
|
|
11495
|
-
};
|
|
11496
|
-
}
|
|
11497
|
-
if (pm2InstanceId !== undefined) {
|
|
11498
|
-
return {
|
|
11499
|
-
role: pm2InstanceId === "0" ? "primary" : "worker",
|
|
11500
|
-
instanceId: pm2InstanceId,
|
|
11501
|
-
env: "pm2-cluster"
|
|
11502
|
-
};
|
|
11503
|
-
}
|
|
11504
|
-
return {
|
|
11505
|
-
role: "primary",
|
|
11506
|
-
instanceId: null,
|
|
11507
|
-
env: "standalone"
|
|
11508
|
-
};
|
|
11509
|
-
}
|
|
11510
|
-
|
|
11511
11486
|
// utils/scanSources.ts
|
|
11512
11487
|
init_dist();
|
|
11513
11488
|
|
|
@@ -11598,7 +11573,7 @@ var corsHook = {
|
|
|
11598
11573
|
};
|
|
11599
11574
|
var cors_default = corsHook;
|
|
11600
11575
|
|
|
11601
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
11576
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/util.js
|
|
11602
11577
|
var nameStartChar = ":A-Za-z_\\u00C0-\\u00D6\\u00D8-\\u00F6\\u00F8-\\u02FF\\u0370-\\u037D\\u037F-\\u1FFF\\u200C-\\u200D\\u2070-\\u218F\\u2C00-\\u2FEF\\u3001-\\uD7FF\\uF900-\\uFDCF\\uFDF0-\\uFFFD";
|
|
11603
11578
|
var nameChar = nameStartChar + "\\-.\\d\\u00B7\\u0300-\\u036F\\u203F-\\u2040";
|
|
11604
11579
|
var nameRegexp = "[" + nameStartChar + "][" + nameChar + "]*";
|
|
@@ -11626,7 +11601,7 @@ function isExist(v) {
|
|
|
11626
11601
|
return typeof v !== "undefined";
|
|
11627
11602
|
}
|
|
11628
11603
|
|
|
11629
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
11604
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/validator.js
|
|
11630
11605
|
var defaultOptions2 = {
|
|
11631
11606
|
allowBooleanAttributes: false,
|
|
11632
11607
|
unpairedTags: []
|
|
@@ -11928,7 +11903,7 @@ function getPositionFromMatch(match) {
|
|
|
11928
11903
|
return match.startIndex + match[1].length;
|
|
11929
11904
|
}
|
|
11930
11905
|
|
|
11931
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
11906
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/xmlparser/OptionsBuilder.js
|
|
11932
11907
|
var defaultOptions3 = {
|
|
11933
11908
|
preserveOrder: false,
|
|
11934
11909
|
attributeNamePrefix: "@_",
|
|
@@ -11972,7 +11947,7 @@ var buildOptions = function(options) {
|
|
|
11972
11947
|
return Object.assign({}, defaultOptions3, options);
|
|
11973
11948
|
};
|
|
11974
11949
|
|
|
11975
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
11950
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/xmlparser/xmlNode.js
|
|
11976
11951
|
var METADATA_SYMBOL;
|
|
11977
11952
|
if (typeof Symbol !== "function") {
|
|
11978
11953
|
METADATA_SYMBOL = "@@xmlMetadata";
|
|
@@ -12008,7 +11983,7 @@ class XmlNode {
|
|
|
12008
11983
|
}
|
|
12009
11984
|
}
|
|
12010
11985
|
|
|
12011
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
11986
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/xmlparser/DocTypeReader.js
|
|
12012
11987
|
class DocTypeReader {
|
|
12013
11988
|
constructor(processEntities) {
|
|
12014
11989
|
this.suppressValidationErr = !processEntities;
|
|
@@ -12385,7 +12360,7 @@ function parse_int(numStr, base) {
|
|
|
12385
12360
|
throw new Error("parseInt, Number.parseInt, window.parseInt are not supported");
|
|
12386
12361
|
}
|
|
12387
12362
|
|
|
12388
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
12363
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/ignoreAttributes.js
|
|
12389
12364
|
function getIgnoreAttributesFn(ignoreAttributes) {
|
|
12390
12365
|
if (typeof ignoreAttributes === "function") {
|
|
12391
12366
|
return ignoreAttributes;
|
|
@@ -12405,7 +12380,7 @@ function getIgnoreAttributesFn(ignoreAttributes) {
|
|
|
12405
12380
|
return () => false;
|
|
12406
12381
|
}
|
|
12407
12382
|
|
|
12408
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
12383
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/xmlparser/OrderedObjParser.js
|
|
12409
12384
|
class OrderedObjParser {
|
|
12410
12385
|
constructor(options) {
|
|
12411
12386
|
this.options = options;
|
|
@@ -12428,8 +12403,8 @@ class OrderedObjParser {
|
|
|
12428
12403
|
copyright: { regex: /&(copy|#169);/g, val: "\xA9" },
|
|
12429
12404
|
reg: { regex: /&(reg|#174);/g, val: "\xAE" },
|
|
12430
12405
|
inr: { regex: /&(inr|#8377);/g, val: "\u20B9" },
|
|
12431
|
-
num_dec: { regex: /&#([0-9]{1,7});/g, val: (_, str) =>
|
|
12432
|
-
num_hex: { regex: /&#x([0-9a-fA-F]{1,6});/g, val: (_, str) =>
|
|
12406
|
+
num_dec: { regex: /&#([0-9]{1,7});/g, val: (_, str) => fromCodePoint(str, 10, "&#") },
|
|
12407
|
+
num_hex: { regex: /&#x([0-9a-fA-F]{1,6});/g, val: (_, str) => fromCodePoint(str, 16, "&#x") }
|
|
12433
12408
|
};
|
|
12434
12409
|
this.addExternalEntities = addExternalEntities;
|
|
12435
12410
|
this.parseXml = parseXml;
|
|
@@ -12907,8 +12882,16 @@ function parseValue(val, shouldParse, options) {
|
|
|
12907
12882
|
}
|
|
12908
12883
|
}
|
|
12909
12884
|
}
|
|
12885
|
+
function fromCodePoint(str, base, prefix) {
|
|
12886
|
+
const codePoint = Number.parseInt(str, base);
|
|
12887
|
+
if (codePoint >= 0 && codePoint <= 1114111) {
|
|
12888
|
+
return String.fromCodePoint(codePoint);
|
|
12889
|
+
} else {
|
|
12890
|
+
return prefix + str + ";";
|
|
12891
|
+
}
|
|
12892
|
+
}
|
|
12910
12893
|
|
|
12911
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
12894
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/xmlparser/node2json.js
|
|
12912
12895
|
var METADATA_SYMBOL2 = XmlNode.getMetaDataSymbol();
|
|
12913
12896
|
function prettify(node, options) {
|
|
12914
12897
|
return compress(node, options);
|
|
@@ -13002,7 +12985,7 @@ function isLeafTag(obj, options) {
|
|
|
13002
12985
|
return false;
|
|
13003
12986
|
}
|
|
13004
12987
|
|
|
13005
|
-
// ../../node_modules/.bun/fast-xml-parser@5.3.
|
|
12988
|
+
// ../../node_modules/.bun/fast-xml-parser@5.3.4/node_modules/fast-xml-parser/src/xmlparser/XMLParser.js
|
|
13006
12989
|
class XMLParser {
|
|
13007
12990
|
constructor(options) {
|
|
13008
12991
|
this.externalEntities = {};
|
|
@@ -13109,6 +13092,9 @@ class CacheKeys {
|
|
|
13109
13092
|
static roleInfo(roleCode) {
|
|
13110
13093
|
return `role:info:${roleCode}`;
|
|
13111
13094
|
}
|
|
13095
|
+
static roleMenus(roleCode) {
|
|
13096
|
+
return `role:menus:${roleCode}`;
|
|
13097
|
+
}
|
|
13112
13098
|
static roleApis(roleCode) {
|
|
13113
13099
|
return `role:apis:${roleCode}`;
|
|
13114
13100
|
}
|
|
@@ -13694,6 +13680,25 @@ class CacheHelper {
|
|
|
13694
13680
|
}
|
|
13695
13681
|
return trimmed;
|
|
13696
13682
|
}
|
|
13683
|
+
assertMenuPathname(value, errorPrefix) {
|
|
13684
|
+
if (typeof value !== "string") {
|
|
13685
|
+
throw new Error(`${errorPrefix} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);
|
|
13686
|
+
}
|
|
13687
|
+
const trimmed = value.trim();
|
|
13688
|
+
if (!trimmed) {
|
|
13689
|
+
throw new Error(`${errorPrefix} \u4E0D\u5141\u8BB8\u4E3A\u7A7A\u5B57\u7B26\u4E32`);
|
|
13690
|
+
}
|
|
13691
|
+
if (!trimmed.startsWith("/")) {
|
|
13692
|
+
throw new Error(`${errorPrefix} \u5FC5\u987B\u662F pathname\uFF08\u4EE5 / \u5F00\u5934\uFF09`);
|
|
13693
|
+
}
|
|
13694
|
+
if (trimmed.includes(" ")) {
|
|
13695
|
+
throw new Error(`${errorPrefix} \u4E0D\u5141\u8BB8\u5305\u542B\u7A7A\u683C`);
|
|
13696
|
+
}
|
|
13697
|
+
if (trimmed.length > 1 && trimmed.endsWith("/")) {
|
|
13698
|
+
throw new Error(`${errorPrefix} \u4E0D\u5141\u8BB8\u4EE5 / \u7ED3\u5C3E`);
|
|
13699
|
+
}
|
|
13700
|
+
return trimmed;
|
|
13701
|
+
}
|
|
13697
13702
|
assertApiPathList(value, roleCode) {
|
|
13698
13703
|
if (value === null || value === undefined)
|
|
13699
13704
|
return [];
|
|
@@ -13721,6 +13726,33 @@ class CacheHelper {
|
|
|
13721
13726
|
}
|
|
13722
13727
|
return out;
|
|
13723
13728
|
}
|
|
13729
|
+
assertMenuPathList(value, roleCode) {
|
|
13730
|
+
if (value === null || value === undefined)
|
|
13731
|
+
return [];
|
|
13732
|
+
let list = value;
|
|
13733
|
+
if (typeof list === "string") {
|
|
13734
|
+
const trimmed = list.trim();
|
|
13735
|
+
if (trimmed === "" || trimmed === "null") {
|
|
13736
|
+
return [];
|
|
13737
|
+
}
|
|
13738
|
+
if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
|
|
13739
|
+
try {
|
|
13740
|
+
list = JSON.parse(trimmed);
|
|
13741
|
+
} catch {
|
|
13742
|
+
throw new Error(`\u89D2\u8272\u83DC\u5355\u6743\u9650\u6570\u636E\u4E0D\u5408\u6CD5\uFF1Aaddon_admin_role.menus JSON \u89E3\u6790\u5931\u8D25\uFF0CroleCode=${roleCode}`);
|
|
13743
|
+
}
|
|
13744
|
+
}
|
|
13745
|
+
}
|
|
13746
|
+
if (!Array.isArray(list)) {
|
|
13747
|
+
const typeLabel = typeof list;
|
|
13748
|
+
throw new Error(`\u89D2\u8272\u83DC\u5355\u6743\u9650\u6570\u636E\u4E0D\u5408\u6CD5\uFF1Aaddon_admin_role.menus \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4\u6216 JSON \u6570\u7EC4\u5B57\u7B26\u4E32\uFF0CroleCode=${roleCode}\uFF0Ctype=${typeLabel}`);
|
|
13749
|
+
}
|
|
13750
|
+
const out = [];
|
|
13751
|
+
for (const item of list) {
|
|
13752
|
+
out.push(this.assertMenuPathname(item, `\u89D2\u8272\u83DC\u5355\u6743\u9650\u6570\u636E\u4E0D\u5408\u6CD5\uFF1Aaddon_admin_role.menus \u5143\u7D20\uFF0CroleCode=${roleCode}`));
|
|
13753
|
+
}
|
|
13754
|
+
return out;
|
|
13755
|
+
}
|
|
13724
13756
|
async cacheApis() {
|
|
13725
13757
|
try {
|
|
13726
13758
|
const tableExists = await this.db.tableExists("addon_admin_api");
|
|
@@ -13807,6 +13839,56 @@ class CacheHelper {
|
|
|
13807
13839
|
});
|
|
13808
13840
|
}
|
|
13809
13841
|
}
|
|
13842
|
+
async rebuildRoleMenuPermissions() {
|
|
13843
|
+
try {
|
|
13844
|
+
const roleTableExists = await this.db.tableExists("addon_admin_role");
|
|
13845
|
+
if (!roleTableExists.data) {
|
|
13846
|
+
Logger.warn("\u26A0\uFE0F \u89D2\u8272\u8868\u4E0D\u5B58\u5728\uFF0C\u8DF3\u8FC7\u89D2\u8272\u83DC\u5355\u6743\u9650\u7F13\u5B58");
|
|
13847
|
+
return;
|
|
13848
|
+
}
|
|
13849
|
+
const roles = await this.db.getAll({
|
|
13850
|
+
table: "addon_admin_role",
|
|
13851
|
+
fields: ["code", "menus"]
|
|
13852
|
+
});
|
|
13853
|
+
const roleMenuPathsMap = new Map;
|
|
13854
|
+
for (const role of roles.data.lists) {
|
|
13855
|
+
if (!role?.code)
|
|
13856
|
+
continue;
|
|
13857
|
+
const menuPaths = this.assertMenuPathList(role.menus, role.code);
|
|
13858
|
+
roleMenuPathsMap.set(role.code, menuPaths);
|
|
13859
|
+
}
|
|
13860
|
+
const roleCodes = Array.from(roleMenuPathsMap.keys());
|
|
13861
|
+
if (roleCodes.length === 0) {
|
|
13862
|
+
Logger.info("\u2705 \u6CA1\u6709\u9700\u8981\u7F13\u5B58\u7684\u89D2\u8272\u83DC\u5355\u6743\u9650");
|
|
13863
|
+
return;
|
|
13864
|
+
}
|
|
13865
|
+
const roleKeys = roleCodes.map((code) => CacheKeys.roleMenus(code));
|
|
13866
|
+
await this.redis.delBatch(roleKeys);
|
|
13867
|
+
const items = [];
|
|
13868
|
+
for (const roleCode of roleCodes) {
|
|
13869
|
+
const menuPaths = roleMenuPathsMap.get(roleCode) || [];
|
|
13870
|
+
const members = Array.from(new Set(menuPaths)).sort();
|
|
13871
|
+
if (members.length > 0) {
|
|
13872
|
+
items.push({ key: CacheKeys.roleMenus(roleCode), members });
|
|
13873
|
+
}
|
|
13874
|
+
}
|
|
13875
|
+
if (items.length > 0) {
|
|
13876
|
+
await this.redis.saddBatch(items);
|
|
13877
|
+
}
|
|
13878
|
+
} catch (error) {
|
|
13879
|
+
Logger.error({ err: error, msg: "\u26A0\uFE0F \u89D2\u8272\u83DC\u5355\u6743\u9650\u7F13\u5B58\u5F02\u5E38\uFF08\u5C06\u963B\u65AD\u542F\u52A8\uFF09" });
|
|
13880
|
+
throw new CoreError({
|
|
13881
|
+
kind: "runtime",
|
|
13882
|
+
message: "\u26A0\uFE0F \u89D2\u8272\u83DC\u5355\u6743\u9650\u7F13\u5B58\u5F02\u5E38\uFF08\u5C06\u963B\u65AD\u542F\u52A8\uFF09",
|
|
13883
|
+
logged: true,
|
|
13884
|
+
cause: error,
|
|
13885
|
+
meta: {
|
|
13886
|
+
subsystem: "cache",
|
|
13887
|
+
operation: "rebuildRoleMenuPermissions"
|
|
13888
|
+
}
|
|
13889
|
+
});
|
|
13890
|
+
}
|
|
13891
|
+
}
|
|
13810
13892
|
async refreshRoleApiPermissions(roleCode, apiPaths) {
|
|
13811
13893
|
if (!roleCode || typeof roleCode !== "string") {
|
|
13812
13894
|
throw new Error("roleCode \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
@@ -13826,10 +13908,30 @@ class CacheHelper {
|
|
|
13826
13908
|
await this.redis.sadd(roleKey, members);
|
|
13827
13909
|
}
|
|
13828
13910
|
}
|
|
13911
|
+
async refreshRoleMenuPermissions(roleCode, menuPaths) {
|
|
13912
|
+
if (!roleCode || typeof roleCode !== "string") {
|
|
13913
|
+
throw new Error("roleCode \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
13914
|
+
}
|
|
13915
|
+
if (!Array.isArray(menuPaths)) {
|
|
13916
|
+
throw new Error("menuPaths \u5FC5\u987B\u662F\u6570\u7EC4");
|
|
13917
|
+
}
|
|
13918
|
+
const normalizedPaths = menuPaths.map((p) => this.assertMenuPathname(p, `refreshRoleMenuPermissions: menuPaths \u5143\u7D20\uFF0CroleCode=${roleCode}`));
|
|
13919
|
+
const roleKey = CacheKeys.roleMenus(roleCode);
|
|
13920
|
+
if (normalizedPaths.length === 0) {
|
|
13921
|
+
await this.redis.del(roleKey);
|
|
13922
|
+
return;
|
|
13923
|
+
}
|
|
13924
|
+
const members = Array.from(new Set(normalizedPaths));
|
|
13925
|
+
await this.redis.del(roleKey);
|
|
13926
|
+
if (members.length > 0) {
|
|
13927
|
+
await this.redis.sadd(roleKey, members);
|
|
13928
|
+
}
|
|
13929
|
+
}
|
|
13829
13930
|
async cacheAll() {
|
|
13830
13931
|
await this.cacheApis();
|
|
13831
13932
|
await this.cacheMenus();
|
|
13832
13933
|
await this.rebuildRoleApiPermissions();
|
|
13934
|
+
await this.rebuildRoleMenuPermissions();
|
|
13833
13935
|
}
|
|
13834
13936
|
async getApis() {
|
|
13835
13937
|
try {
|
|
@@ -13858,6 +13960,15 @@ class CacheHelper {
|
|
|
13858
13960
|
return [];
|
|
13859
13961
|
}
|
|
13860
13962
|
}
|
|
13963
|
+
async getRoleMenuPermissions(roleCode) {
|
|
13964
|
+
try {
|
|
13965
|
+
const permissions = await this.redis.smembers(CacheKeys.roleMenus(roleCode));
|
|
13966
|
+
return permissions || [];
|
|
13967
|
+
} catch (error) {
|
|
13968
|
+
Logger.error({ err: error, roleCode, msg: "\u83B7\u53D6\u89D2\u8272\u83DC\u5355\u6743\u9650\u7F13\u5B58\u5931\u8D25" });
|
|
13969
|
+
return [];
|
|
13970
|
+
}
|
|
13971
|
+
}
|
|
13861
13972
|
async checkRolePermission(roleCode, apiPath) {
|
|
13862
13973
|
try {
|
|
13863
13974
|
const pathname = this.assertApiPathname(apiPath, "checkRolePermission: apiPath");
|
|
@@ -13867,6 +13978,15 @@ class CacheHelper {
|
|
|
13867
13978
|
return false;
|
|
13868
13979
|
}
|
|
13869
13980
|
}
|
|
13981
|
+
async checkRoleMenuPermission(roleCode, menuPath) {
|
|
13982
|
+
try {
|
|
13983
|
+
const pathname = this.assertMenuPathname(menuPath, "checkRoleMenuPermission: menuPath");
|
|
13984
|
+
return await this.redis.sismember(CacheKeys.roleMenus(roleCode), pathname);
|
|
13985
|
+
} catch (error) {
|
|
13986
|
+
Logger.error({ err: error, roleCode, msg: "\u68C0\u67E5\u89D2\u8272\u83DC\u5355\u6743\u9650\u5931\u8D25" });
|
|
13987
|
+
return false;
|
|
13988
|
+
}
|
|
13989
|
+
}
|
|
13870
13990
|
async deleteRolePermissions(roleCode) {
|
|
13871
13991
|
try {
|
|
13872
13992
|
const result = await this.redis.del(CacheKeys.roleApis(roleCode));
|
|
@@ -13880,6 +14000,19 @@ class CacheHelper {
|
|
|
13880
14000
|
return false;
|
|
13881
14001
|
}
|
|
13882
14002
|
}
|
|
14003
|
+
async deleteRoleMenuPermissions(roleCode) {
|
|
14004
|
+
try {
|
|
14005
|
+
const result = await this.redis.del(CacheKeys.roleMenus(roleCode));
|
|
14006
|
+
if (result > 0) {
|
|
14007
|
+
Logger.info(`\u2705 \u5DF2\u5220\u9664\u89D2\u8272 ${roleCode} \u7684\u83DC\u5355\u6743\u9650\u7F13\u5B58`);
|
|
14008
|
+
return true;
|
|
14009
|
+
}
|
|
14010
|
+
return false;
|
|
14011
|
+
} catch (error) {
|
|
14012
|
+
Logger.error({ err: error, roleCode, msg: "\u5220\u9664\u89D2\u8272\u83DC\u5355\u6743\u9650\u7F13\u5B58\u5931\u8D25" });
|
|
14013
|
+
return false;
|
|
14014
|
+
}
|
|
14015
|
+
}
|
|
13883
14016
|
}
|
|
13884
14017
|
|
|
13885
14018
|
// plugins/cache.ts
|
|
@@ -16293,6 +16426,52 @@ class RedisHelper {
|
|
|
16293
16426
|
return null;
|
|
16294
16427
|
}
|
|
16295
16428
|
}
|
|
16429
|
+
async tryAcquireLock(key, token, ttlMs) {
|
|
16430
|
+
try {
|
|
16431
|
+
if (!key || typeof key !== "string") {
|
|
16432
|
+
throw new Error("tryAcquireLock: key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
16433
|
+
}
|
|
16434
|
+
if (!token || typeof token !== "string") {
|
|
16435
|
+
throw new Error("tryAcquireLock: token \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
16436
|
+
}
|
|
16437
|
+
if (!(typeof ttlMs === "number" && Number.isFinite(ttlMs) && ttlMs > 0)) {
|
|
16438
|
+
throw new Error("tryAcquireLock: ttlMs \u5FC5\u987B\u662F\u6B63\u6570");
|
|
16439
|
+
}
|
|
16440
|
+
const pkey = `${this.prefix}${key}`;
|
|
16441
|
+
const startTime = Date.now();
|
|
16442
|
+
const ttlMsString = String(Math.floor(ttlMs));
|
|
16443
|
+
const res = await this.client.set(pkey, token, "NX", "PX", ttlMsString);
|
|
16444
|
+
const duration = Date.now() - startTime;
|
|
16445
|
+
this.logSlow("SET NX PX", pkey, duration, { ttlMs });
|
|
16446
|
+
return res === "OK";
|
|
16447
|
+
} catch (error) {
|
|
16448
|
+
Logger.error({ err: error, msg: "Redis tryAcquireLock \u9519\u8BEF" });
|
|
16449
|
+
return false;
|
|
16450
|
+
}
|
|
16451
|
+
}
|
|
16452
|
+
async releaseLock(key, token) {
|
|
16453
|
+
try {
|
|
16454
|
+
if (!key || typeof key !== "string") {
|
|
16455
|
+
throw new Error("releaseLock: key \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
16456
|
+
}
|
|
16457
|
+
if (!token || typeof token !== "string") {
|
|
16458
|
+
throw new Error("releaseLock: token \u5FC5\u987B\u662F\u975E\u7A7A\u5B57\u7B26\u4E32");
|
|
16459
|
+
}
|
|
16460
|
+
const pkey = `${this.prefix}${key}`;
|
|
16461
|
+
const startTime = Date.now();
|
|
16462
|
+
const current = await this.client.get(pkey);
|
|
16463
|
+
if (current !== token) {
|
|
16464
|
+
return false;
|
|
16465
|
+
}
|
|
16466
|
+
const deleted = await this.client.del(pkey);
|
|
16467
|
+
const duration = Date.now() - startTime;
|
|
16468
|
+
this.logSlow("GET+DEL", pkey, duration);
|
|
16469
|
+
return deleted > 0;
|
|
16470
|
+
} catch (error) {
|
|
16471
|
+
Logger.error({ err: error, msg: "Redis releaseLock \u9519\u8BEF" });
|
|
16472
|
+
return false;
|
|
16473
|
+
}
|
|
16474
|
+
}
|
|
16296
16475
|
async getString(key) {
|
|
16297
16476
|
try {
|
|
16298
16477
|
const pkey = `${this.prefix}${key}`;
|
|
@@ -16394,7 +16573,9 @@ class RedisHelper {
|
|
|
16394
16573
|
const startTime = Date.now();
|
|
16395
16574
|
const res = await this.client.sadd(pkey, ...members);
|
|
16396
16575
|
const duration = Date.now() - startTime;
|
|
16397
|
-
this.logSlow("SADD", pkey, duration, {
|
|
16576
|
+
this.logSlow("SADD", pkey, duration, {
|
|
16577
|
+
membersCount: members.length
|
|
16578
|
+
});
|
|
16398
16579
|
return res;
|
|
16399
16580
|
} catch (error) {
|
|
16400
16581
|
Logger.error({ err: error, msg: "Redis sadd \u9519\u8BEF" });
|
|
@@ -16884,17 +17065,57 @@ class Befly {
|
|
|
16884
17065
|
});
|
|
16885
17066
|
this.plugins = await loadPlugins(plugins, this.context);
|
|
16886
17067
|
this.assertStartContextReady();
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
const
|
|
16891
|
-
const
|
|
16892
|
-
|
|
16893
|
-
|
|
17068
|
+
const syncLockKey = "sync:lock";
|
|
17069
|
+
const syncReadyKey = "sync:ready";
|
|
17070
|
+
const syncLockTtlMs = 10 * 60 * 1000;
|
|
17071
|
+
const syncWaitReadyMaxMs = 120 * 1000;
|
|
17072
|
+
const syncWaitPollMs = 250;
|
|
17073
|
+
const syncToken = `${process.pid}:${Bun.nanoseconds()}`;
|
|
17074
|
+
const ctx = this.context;
|
|
17075
|
+
const acquired = await ctx.redis.tryAcquireLock(syncLockKey, syncToken, syncLockTtlMs);
|
|
17076
|
+
if (acquired) {
|
|
17077
|
+
Logger.info({ key: syncLockKey, msg: "\u2705 \u5DF2\u83B7\u53D6\u542F\u52A8\u540C\u6B65\u9501\uFF0C\u5C06\u6267\u884C\u81EA\u52A8\u540C\u6B65" });
|
|
17078
|
+
await ctx.redis.del(syncReadyKey);
|
|
17079
|
+
try {
|
|
17080
|
+
await new SyncTable(ctx).run(tables);
|
|
17081
|
+
await syncApi(ctx, apis);
|
|
17082
|
+
await syncMenu(ctx, checkedMenus);
|
|
17083
|
+
const devEmail = this.config.devEmail;
|
|
17084
|
+
const devPassword = this.config.devPassword;
|
|
17085
|
+
if (typeof devEmail === "string" && devEmail.length > 0 && typeof devPassword === "string" && devPassword.length > 0) {
|
|
17086
|
+
await syncDev(ctx, { devEmail, devPassword });
|
|
17087
|
+
} else {
|
|
17088
|
+
Logger.debug("\u8DF3\u8FC7 syncDev\uFF1A\u672A\u914D\u7F6E devEmail/devPassword");
|
|
17089
|
+
}
|
|
17090
|
+
await syncCache(ctx);
|
|
17091
|
+
await ctx.redis.setString(syncReadyKey, String(Date.now()), 60 * 60);
|
|
17092
|
+
} finally {
|
|
17093
|
+
const released = await ctx.redis.releaseLock(syncLockKey, syncToken);
|
|
17094
|
+
if (!released) {
|
|
17095
|
+
Logger.warn({ key: syncLockKey, msg: "\u540C\u6B65\u9501\u672A\u80FD\u4E3B\u52A8\u91CA\u653E\uFF08\u5C06\u4F9D\u8D56 TTL \u81EA\u52A8\u91CA\u653E\uFF09" });
|
|
17096
|
+
}
|
|
17097
|
+
}
|
|
16894
17098
|
} else {
|
|
16895
|
-
Logger.
|
|
17099
|
+
Logger.info({ key: syncLockKey, msg: "\u542F\u52A8\u540C\u6B65\u9501\u88AB\u5360\u7528\uFF1A\u7B49\u5F85\u540C\u6B65\u5B8C\u6210\u6807\u8BB0" });
|
|
17100
|
+
const waitStart = Date.now();
|
|
17101
|
+
while (true) {
|
|
17102
|
+
const ready = await ctx.redis.getString(syncReadyKey);
|
|
17103
|
+
if (typeof ready === "string" && ready.length > 0) {
|
|
17104
|
+
Logger.info({ key: syncReadyKey, msg: "\u2705 \u68C0\u6D4B\u5230\u540C\u6B65\u5B8C\u6210\u6807\u8BB0\uFF0C\u5C06\u8DF3\u8FC7\u81EA\u52A8\u540C\u6B65" });
|
|
17105
|
+
break;
|
|
17106
|
+
}
|
|
17107
|
+
const elapsed = Date.now() - waitStart;
|
|
17108
|
+
if (elapsed >= syncWaitReadyMaxMs) {
|
|
17109
|
+
throw new CoreError({
|
|
17110
|
+
kind: "runtime",
|
|
17111
|
+
message: `\u542F\u52A8\u7B49\u5F85\u540C\u6B65\u5B8C\u6210\u8D85\u65F6\uFF08${syncWaitReadyMaxMs}ms\uFF09\uFF1A\u8BF7\u68C0\u67E5\u662F\u5426\u6709\u5B9E\u4F8B\u5361\u5728\u540C\u6B65\u9636\u6BB5\u6216 Redis \u9501 TTL \u8FC7\u957F`,
|
|
17112
|
+
logged: true,
|
|
17113
|
+
meta: { subsystem: "start", operation: "waitSyncReady" }
|
|
17114
|
+
});
|
|
17115
|
+
}
|
|
17116
|
+
await Bun.sleep(syncWaitPollMs);
|
|
17117
|
+
}
|
|
16896
17118
|
}
|
|
16897
|
-
await syncCache(this.context);
|
|
16898
17119
|
this.hooks = await loadHooks(hooks);
|
|
16899
17120
|
this.apis = await loadApis(apis);
|
|
16900
17121
|
const apiFetch = apiHandler(this.apis, this.hooks, this.context);
|
|
@@ -16930,10 +17151,7 @@ class Befly {
|
|
|
16930
17151
|
}
|
|
16931
17152
|
});
|
|
16932
17153
|
const finalStartupTime = calcPerfTime(serverStartTime);
|
|
16933
|
-
|
|
16934
|
-
const roleLabel = processRole.role === "primary" ? "\u4E3B\u8FDB\u7A0B" : `\u5DE5\u4F5C\u8FDB\u7A0B #${processRole.instanceId}`;
|
|
16935
|
-
const envLabel = processRole.env === "standalone" ? "" : ` [${processRole.env}]`;
|
|
16936
|
-
Logger.info(`${this.config.appName} \u542F\u52A8\u6210\u529F! (${roleLabel}${envLabel})`);
|
|
17154
|
+
Logger.info(`${this.config.appName} \u542F\u52A8\u6210\u529F!`);
|
|
16937
17155
|
Logger.info(`\u670D\u52A1\u5668\u542F\u52A8\u8017\u65F6: ${finalStartupTime}`);
|
|
16938
17156
|
Logger.info(`\u670D\u52A1\u5668\u76D1\u542C\u5730\u5740: ${server.url}`);
|
|
16939
17157
|
return server;
|