koishi-plugin-forward-hime 1.4.0 → 1.4.1-alpha.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/lib/config.d.ts +1 -0
- package/lib/decorator.d.ts +1 -0
- package/lib/index.js +94 -43
- package/lib/message.d.ts +1 -1
- package/package.json +7 -4
package/lib/config.d.ts
CHANGED
package/lib/decorator.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export declare function defaultDecorator({ head, content }: ForwardMsg): Element
|
|
|
9
9
|
export declare function defaultMiddleware(session: Session): ForwardMsg;
|
|
10
10
|
export declare function MsgMiddlewareCache(session: Session): Promise<void>;
|
|
11
11
|
export declare function MsgDecorator(session: Session, node: ForwardNode): Promise<any>;
|
|
12
|
+
export declare function MsgDecoratorNoRelay(session: Session, node: ForwardNode): Promise<any>;
|
|
12
13
|
export declare function MsgDecoratorFallback(session: Session, node: ForwardNode): Promise<Element[]>;
|
|
13
14
|
export declare function MsgDecoratorFallbackReason(session: Session, node: ForwardNode, reason: string): Promise<Element[]>;
|
|
14
15
|
export {};
|
package/lib/index.js
CHANGED
|
@@ -70,8 +70,8 @@ async function msgCacheFindByUUID(uuid) {
|
|
|
70
70
|
if (cacheNotEnabled()) {
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
|
-
|
|
74
|
-
|
|
73
|
+
const caches = await ctx.cache.entries("msgCache");
|
|
74
|
+
const result = [];
|
|
75
75
|
for await (const item of caches) {
|
|
76
76
|
if (item[1].uuid === uuid) {
|
|
77
77
|
result.push(item);
|
|
@@ -83,7 +83,7 @@ async function msgCacheGetLocalIDByUUID(node, uuid) {
|
|
|
83
83
|
if (cacheNotEnabled()) {
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
|
-
|
|
86
|
+
const caches = await ctx.cache.entries("msgCache");
|
|
87
87
|
for await (const item of caches) {
|
|
88
88
|
if (item[1].uuid === uuid && item[1].platform === node.Platform && item[1].guild === node.Guild && item[1].bot === node.BotID) {
|
|
89
89
|
return item[1].msgid;
|
|
@@ -103,10 +103,11 @@ var createConfig = () => import_koishi2.Schema.intersect([
|
|
|
103
103
|
Newline: import_koishi2.Schema.boolean().description("\u662F\u5426\u6362\u884C").default(true)
|
|
104
104
|
}).description("\u9ED8\u8BA4\u88C5\u9970\u5668"),
|
|
105
105
|
DefaultFallbackMsgPrefix: import_koishi2.Schema.string().description("\u9ED8\u8BA4Fallback\u6D88\u606F\u524D\u7F00").default("[\u6D88\u606F\u964D\u7EA7] "),
|
|
106
|
+
ForwardTimeoutSec: import_koishi2.Schema.number().description("\u8F6C\u53D1\u6162\u901F\u544A\u8B66\u9608\u503C\uFF08\u79D2\uFF09- \u8D85\u8FC7\u8BE5\u65F6\u95F4\u4ECD\u7B49\u5F85\u53D1\u9001\u7ED3\u679C\uFF0C\u907F\u514D\u91CD\u590D\u6D88\u606F").default(60).min(5).max(120),
|
|
106
107
|
MediaRelay: import_koishi2.Schema.object({
|
|
107
108
|
Enabled: import_koishi2.Schema.boolean().description("\u542F\u7528\u5A92\u4F53\u4E2D\u8F6C\uFF08\u4E0B\u8F7D\u540E\u518D\u8F6C\u53D1\uFF09").default(true),
|
|
108
109
|
CacheMinutes: import_koishi2.Schema.number().description("\u5A92\u4F53\u6682\u5B58\u65F6\u95F4\uFF08\u5206\u949F\uFF09").default(10).min(1).max(180),
|
|
109
|
-
RequestTimeoutSec: import_koishi2.Schema.number().description("\u5A92\u4F53\u4E0B\u8F7D\u8D85\u65F6\u65F6\u95F4\uFF08\u79D2\uFF09").default(
|
|
110
|
+
RequestTimeoutSec: import_koishi2.Schema.number().description("\u5A92\u4F53\u4E0B\u8F7D\u8D85\u65F6\u65F6\u95F4\uFF08\u79D2\uFF09").default(30).min(3).max(120),
|
|
110
111
|
MaxFileSizeMB: import_koishi2.Schema.number().description("\u5141\u8BB8\u4E2D\u8F6C\u7684\u5A92\u4F53\u6700\u5927\u5927\u5C0F\uFF08MB\uFF09").default(20).min(1).max(200)
|
|
111
112
|
}).description("\u5A92\u4F53\u4E2D\u8F6C")
|
|
112
113
|
}).description("\u8F6C\u53D1\u683C\u5F0F"),
|
|
@@ -164,7 +165,7 @@ var kook_default = {
|
|
|
164
165
|
// src/decorators/onebot.ts
|
|
165
166
|
var import_koishi4 = require("koishi");
|
|
166
167
|
function cqJsonTranslator(content, elem) {
|
|
167
|
-
|
|
168
|
+
const json = JSON.parse(elem.attrs.data);
|
|
168
169
|
let hit = 0;
|
|
169
170
|
if (json) {
|
|
170
171
|
if (json.prompt) {
|
|
@@ -201,10 +202,10 @@ function getNameFromQQat(elem) {
|
|
|
201
202
|
}
|
|
202
203
|
function Middleware(session) {
|
|
203
204
|
const platform = guessPlatform(session);
|
|
204
|
-
|
|
205
|
+
const sessionTemp = session;
|
|
205
206
|
sessionTemp.platform = platform;
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
const head = defaultMiddleware(sessionTemp).head;
|
|
208
|
+
const newContent = [];
|
|
208
209
|
if (platform === "QQ") {
|
|
209
210
|
IdNameCache.set(session.userId, session.username);
|
|
210
211
|
for (const key in session.elements) {
|
|
@@ -460,7 +461,7 @@ async function MessageSendWithDecorator(ctx2, node, session, Deco) {
|
|
|
460
461
|
const uuid = session.channelId + ":" + session.messageId;
|
|
461
462
|
const content = await Deco(session, node);
|
|
462
463
|
await ctx2.bots[`${node.Platform}:${node.BotID}`].sendMessage(node.Guild, content).then((res) => {
|
|
463
|
-
|
|
464
|
+
const mc = {
|
|
464
465
|
platform: node.Platform,
|
|
465
466
|
bot: node.BotID,
|
|
466
467
|
guild: node.Guild,
|
|
@@ -487,26 +488,56 @@ function sessionTypeArray(session) {
|
|
|
487
488
|
});
|
|
488
489
|
return contentTypes;
|
|
489
490
|
}
|
|
490
|
-
async function MessageForward(ctx2, node, session) {
|
|
491
|
+
async function MessageForward(ctx2, node, session, timeoutSec, relayEnabled) {
|
|
491
492
|
if (!botExistsCheck(ctx2, node)) {
|
|
492
493
|
return;
|
|
493
494
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
)
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
495
|
+
const timeoutMs = (timeoutSec ?? 30) * 1e3;
|
|
496
|
+
const deco = relayEnabled !== false ? MsgDecorator : MsgDecoratorNoRelay;
|
|
497
|
+
function warnIfSlow(promise) {
|
|
498
|
+
const timer = setTimeout(() => {
|
|
499
|
+
logger.warn(
|
|
500
|
+
`[MessageForward] still pending after ${timeoutSec ?? 30}s; awaiting result to prevent duplicate delivery: ${node.Platform}`
|
|
501
|
+
);
|
|
502
|
+
}, timeoutMs);
|
|
503
|
+
return promise.finally(() => clearTimeout(timer));
|
|
504
|
+
}
|
|
505
|
+
function sendDegraded(reason) {
|
|
506
|
+
const fallbackDeco = reason ? (fallbackSession, fallbackNode) => MsgDecoratorFallbackReason(fallbackSession, fallbackNode, reason) : MsgDecoratorFallback;
|
|
507
|
+
MessageSendWithDecorator(ctx2, node, session, fallbackDeco).catch((error) => {
|
|
505
508
|
logger.error(
|
|
506
|
-
`ERROR:<MessageSendFallback ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${
|
|
509
|
+
`ERROR:<MessageSendFallback ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${error}`
|
|
507
510
|
);
|
|
508
511
|
});
|
|
509
|
-
}
|
|
512
|
+
}
|
|
513
|
+
function reasonFromError(error) {
|
|
514
|
+
if (error instanceof MediaRelayError) {
|
|
515
|
+
return `[\u8F6C\u53D1\u5931\u8D25] ${error.userMessage} `;
|
|
516
|
+
}
|
|
517
|
+
return void 0;
|
|
518
|
+
}
|
|
519
|
+
warnIfSlow(MessageSendWithDecorator(ctx2, node, session, deco)).catch(
|
|
520
|
+
(firstError) => {
|
|
521
|
+
logger.error(
|
|
522
|
+
`ERROR:<MessageSend ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${firstError}`
|
|
523
|
+
);
|
|
524
|
+
if (relayEnabled !== false && firstError instanceof MediaRelayError) {
|
|
525
|
+
logger.info(
|
|
526
|
+
`[MessageForward] relay failed, retrying without relay: ${node.Platform}`
|
|
527
|
+
);
|
|
528
|
+
warnIfSlow(
|
|
529
|
+
MessageSendWithDecorator(ctx2, node, session, MsgDecoratorNoRelay)
|
|
530
|
+
).catch((secondError) => {
|
|
531
|
+
logger.error(
|
|
532
|
+
`ERROR:<MessageSendDirect ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${secondError}`
|
|
533
|
+
);
|
|
534
|
+
sendDegraded(reasonFromError(secondError));
|
|
535
|
+
});
|
|
536
|
+
} else {
|
|
537
|
+
sendDegraded(reasonFromError(firstError));
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
);
|
|
510
541
|
}
|
|
511
542
|
async function MessageDelete(ctx2, msg) {
|
|
512
543
|
if (!botExistsCheck(ctx2, { Platform: msg.platform, BotID: msg.bot, Guild: msg.guild })) {
|
|
@@ -548,7 +579,7 @@ function defaultDecorator({ head, content }) {
|
|
|
548
579
|
return msg;
|
|
549
580
|
}
|
|
550
581
|
function defaultMiddleware(session) {
|
|
551
|
-
|
|
582
|
+
const head = [(0, import_koishi6.h)("span", renderTemplate(defaultPrefix, session))];
|
|
552
583
|
if (defaultPrefixNewline) {
|
|
553
584
|
head.push((0, import_koishi6.h)("br"));
|
|
554
585
|
}
|
|
@@ -572,24 +603,21 @@ function msgMiddleCacheFind(uuid) {
|
|
|
572
603
|
return null;
|
|
573
604
|
}
|
|
574
605
|
function MsgToMiddleware(session) {
|
|
575
|
-
|
|
576
|
-
let _platform_in = decorators_exports[session.platform];
|
|
606
|
+
const _platform_in = decorators_exports[session.platform];
|
|
577
607
|
if (_platform_in && typeof _platform_in.Middleware === "function") {
|
|
578
|
-
|
|
579
|
-
} else {
|
|
580
|
-
elems = defaultMiddleware(session);
|
|
608
|
+
return _platform_in.Middleware(session);
|
|
581
609
|
}
|
|
582
|
-
return
|
|
610
|
+
return defaultMiddleware(session);
|
|
583
611
|
}
|
|
584
612
|
async function MsgMiddlewareCache(session) {
|
|
585
|
-
|
|
613
|
+
const elems = MsgToMiddleware(session);
|
|
586
614
|
msgMiddleCacheAppend({ UUID: MsgUUIDFromSession(session), msg: elems });
|
|
587
615
|
logger.debug(`[msgMiddleCache] CACHED`);
|
|
588
616
|
}
|
|
589
617
|
async function MsgDecorator(session, node) {
|
|
590
618
|
let elems;
|
|
591
|
-
|
|
592
|
-
|
|
619
|
+
const _platform_out = decorators_exports[node.Platform];
|
|
620
|
+
const elemCache = msgMiddleCacheFind(MsgUUIDFromSession(session));
|
|
593
621
|
if (elemCache) {
|
|
594
622
|
logger.debug(`[msgMiddleCache] HIT`);
|
|
595
623
|
elems = elemCache;
|
|
@@ -610,9 +638,28 @@ async function MsgDecorator(session, node) {
|
|
|
610
638
|
return defaultDecorator(elems);
|
|
611
639
|
}
|
|
612
640
|
}
|
|
641
|
+
async function MsgDecoratorNoRelay(session, node) {
|
|
642
|
+
let elems;
|
|
643
|
+
const _platform_out = decorators_exports[node.Platform];
|
|
644
|
+
const elemCache = msgMiddleCacheFind(MsgUUIDFromSession(session));
|
|
645
|
+
if (elemCache) {
|
|
646
|
+
elems = elemCache;
|
|
647
|
+
} else {
|
|
648
|
+
elems = MsgToMiddleware(session);
|
|
649
|
+
}
|
|
650
|
+
for (const fn of localDecorators) {
|
|
651
|
+
elems = await fn(session, node, elems);
|
|
652
|
+
}
|
|
653
|
+
logger.debug(`[MsgDecoratorNoRelay] fallback to direct forward`);
|
|
654
|
+
if (_platform_out && typeof _platform_out.Decorator === "function") {
|
|
655
|
+
return _platform_out.Decorator(elems);
|
|
656
|
+
} else {
|
|
657
|
+
return defaultDecorator(elems);
|
|
658
|
+
}
|
|
659
|
+
}
|
|
613
660
|
function defaultDecoratorFallback({ head, content }, reason) {
|
|
614
661
|
let msg = [];
|
|
615
|
-
|
|
662
|
+
const newContent = [];
|
|
616
663
|
newContent.push((0, import_koishi6.h)("span", reason || defaultFallback));
|
|
617
664
|
for (const key in content) {
|
|
618
665
|
if (["img", "audio", "video", "file"].includes(content[key].type)) {
|
|
@@ -625,16 +672,14 @@ function defaultDecoratorFallback({ head, content }, reason) {
|
|
|
625
672
|
return msg;
|
|
626
673
|
}
|
|
627
674
|
async function MsgDecoratorFallback(session, node) {
|
|
628
|
-
let elems =
|
|
629
|
-
elems = defaultMiddleware(session);
|
|
675
|
+
let elems = defaultMiddleware(session);
|
|
630
676
|
for (const fn of localDecorators) {
|
|
631
677
|
elems = await fn(session, node, elems);
|
|
632
678
|
}
|
|
633
679
|
return defaultDecoratorFallback(elems);
|
|
634
680
|
}
|
|
635
681
|
async function MsgDecoratorFallbackReason(session, node, reason) {
|
|
636
|
-
let elems =
|
|
637
|
-
elems = defaultMiddleware(session);
|
|
682
|
+
let elems = defaultMiddleware(session);
|
|
638
683
|
for (const fn of localDecorators) {
|
|
639
684
|
elems = await fn(session, node, elems);
|
|
640
685
|
}
|
|
@@ -642,7 +687,7 @@ async function MsgDecoratorFallbackReason(session, node, reason) {
|
|
|
642
687
|
}
|
|
643
688
|
async function atTranslator(session, _, { head, content }) {
|
|
644
689
|
const newMsg = await new Promise((resolve) => {
|
|
645
|
-
|
|
690
|
+
const newContent = [];
|
|
646
691
|
for (const key in content) {
|
|
647
692
|
const element = content[key];
|
|
648
693
|
if (element.type === "at") {
|
|
@@ -666,9 +711,9 @@ async function quoteTranslator(session, node, { head, content }) {
|
|
|
666
711
|
const key = session.channelId + ":" + session.quote.id;
|
|
667
712
|
const cache = await msgCacheFindByKey(key);
|
|
668
713
|
if (cache) {
|
|
669
|
-
|
|
714
|
+
const msgid = await msgCacheGetLocalIDByUUID(node, cache.uuid);
|
|
670
715
|
if (msgid) {
|
|
671
|
-
|
|
716
|
+
const newHead = [(0, import_koishi6.h)("quote", { id: msgid })].concat(head);
|
|
672
717
|
return { head: newHead, content };
|
|
673
718
|
} else {
|
|
674
719
|
logger.error(`[msgCacheGetLocalIDByUUID] ${cache.uuid} not found`);
|
|
@@ -712,7 +757,7 @@ function apply(ctx2, cfg) {
|
|
|
712
757
|
session.platform,
|
|
713
758
|
session.channelId + ":" + session.messageId
|
|
714
759
|
);
|
|
715
|
-
|
|
760
|
+
const uuid = MsgUUIDFromSession(session);
|
|
716
761
|
msgCache({
|
|
717
762
|
platform: session.platform,
|
|
718
763
|
bot: group.Nodes[k].BotID,
|
|
@@ -732,7 +777,13 @@ function apply(ctx2, cfg) {
|
|
|
732
777
|
const group = cfg.ForwardGroups[hitGroup[g]];
|
|
733
778
|
for (const k in group.Nodes) {
|
|
734
779
|
if (group.Nodes[k].Guild !== session.channelId) {
|
|
735
|
-
MessageForward(
|
|
780
|
+
MessageForward(
|
|
781
|
+
ctx2,
|
|
782
|
+
group.Nodes[k],
|
|
783
|
+
session,
|
|
784
|
+
cfg.ForwardTimeoutSec,
|
|
785
|
+
cfg.MediaRelay.Enabled
|
|
786
|
+
);
|
|
736
787
|
}
|
|
737
788
|
}
|
|
738
789
|
}
|
package/lib/message.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Context, Session } from "koishi";
|
|
2
2
|
import { ForwardNode } from "./config";
|
|
3
3
|
import { MsgCache } from "./cache";
|
|
4
|
-
export declare function MessageForward(ctx: Context, node: ForwardNode, session: Session): Promise<void>;
|
|
4
|
+
export declare function MessageForward(ctx: Context, node: ForwardNode, session: Session, timeoutSec?: number, relayEnabled?: boolean): Promise<void>;
|
|
5
5
|
export declare function MessageDelete(ctx: Context, msg: MsgCache): Promise<void>;
|
|
6
6
|
export declare function MessageEdit(ctx: Context, node: ForwardNode, _session: Session): Promise<void>;
|
|
7
7
|
export declare function MsgUUIDFromSession(session: Session): string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-forward-hime",
|
|
3
3
|
"description": "多群组消息互通",
|
|
4
|
-
"version": "1.4.
|
|
4
|
+
"version": "1.4.1-alpha.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "xianii",
|
|
7
7
|
"email": "jiyucheng007@gmail.com"
|
|
@@ -35,22 +35,25 @@
|
|
|
35
35
|
"koishi": "^4.18.7"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
+
"@eslint/compat": "^2.1.0",
|
|
39
|
+
"@eslint/js": "^10.0.1",
|
|
38
40
|
"@koishijs/cache": "^2.0.0",
|
|
39
41
|
"@types/node": "^22.15.0",
|
|
40
42
|
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
|
41
43
|
"@typescript-eslint/parser": "^7.13.0",
|
|
44
|
+
"esbuild": "^0.25.9",
|
|
42
45
|
"eslint": "^9.4.0",
|
|
46
|
+
"eslint-config-prettier": "^9.1.0",
|
|
43
47
|
"eslint-plugin-import": "^2.31.0",
|
|
44
48
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|
|
45
|
-
"eslint-config-prettier": "^9.1.0",
|
|
46
49
|
"eslint-plugin-prettier": "^5.1.3",
|
|
47
50
|
"eslint-plugin-unused-imports": "^4.0.0",
|
|
48
|
-
"esbuild": "^0.25.9",
|
|
49
51
|
"husky": "^9.0.11",
|
|
50
52
|
"koishi": "^4.18.7",
|
|
51
53
|
"lint-staged": "^15.2.7",
|
|
52
54
|
"prettier": "^3.3.2",
|
|
53
|
-
"typescript": "~5.4.5"
|
|
55
|
+
"typescript": "~5.4.5",
|
|
56
|
+
"typescript-eslint": "^8.62.0"
|
|
54
57
|
},
|
|
55
58
|
"scripts": {
|
|
56
59
|
"prepare": "husky",
|