koishi-plugin-forward-hime 1.4.0 → 1.4.1-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/config.d.ts +1 -0
- package/lib/decorator.d.ts +1 -0
- package/lib/index.js +93 -41
- 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,6 +103,7 @@ 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\u603B\u8D85\u65F6\u65F6\u95F4\uFF08\u79D2\uFF09- \u542B\u5A92\u4F53\u4E0B\u8F7D\u4E0E\u53D1\u9001\uFF0C\u8D85\u65F6\u5219\u964D\u7EA7").default(30).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),
|
|
@@ -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,57 @@ 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
|
-
|
|
495
|
+
const timeoutMs = (timeoutSec ?? 30) * 1e3;
|
|
496
|
+
const deco = relayEnabled !== false ? MsgDecorator : MsgDecoratorNoRelay;
|
|
497
|
+
function withTimeout(promise) {
|
|
498
|
+
const timeoutPromise = new Promise(
|
|
499
|
+
(_, reject) => setTimeout(() => reject(new Error("forward total timeout")), timeoutMs)
|
|
497
500
|
);
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
) : MsgDecoratorFallback;
|
|
504
|
-
MessageSendWithDecorator(ctx2, node, session, fallbackDeco).catch((error2) => {
|
|
501
|
+
return Promise.race([promise, timeoutPromise]);
|
|
502
|
+
}
|
|
503
|
+
function sendDegraded(reason) {
|
|
504
|
+
const fallbackDeco = reason ? (fallbackSession, fallbackNode) => MsgDecoratorFallbackReason(fallbackSession, fallbackNode, reason) : MsgDecoratorFallback;
|
|
505
|
+
MessageSendWithDecorator(ctx2, node, session, fallbackDeco).catch((error) => {
|
|
505
506
|
logger.error(
|
|
506
|
-
`ERROR:<MessageSendFallback ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${
|
|
507
|
+
`ERROR:<MessageSendFallback ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${error}`
|
|
507
508
|
);
|
|
508
509
|
});
|
|
509
|
-
}
|
|
510
|
+
}
|
|
511
|
+
function reasonFromError(error) {
|
|
512
|
+
if (error instanceof MediaRelayError) {
|
|
513
|
+
return `[\u8F6C\u53D1\u5931\u8D25] ${error.userMessage} `;
|
|
514
|
+
}
|
|
515
|
+
if (error instanceof Error && error.message === "forward total timeout") {
|
|
516
|
+
return "[\u8F6C\u53D1\u8D85\u65F6] ";
|
|
517
|
+
}
|
|
518
|
+
return void 0;
|
|
519
|
+
}
|
|
520
|
+
withTimeout(MessageSendWithDecorator(ctx2, node, session, deco)).catch(
|
|
521
|
+
(firstError) => {
|
|
522
|
+
logger.error(
|
|
523
|
+
`ERROR:<MessageSend ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${firstError}`
|
|
524
|
+
);
|
|
525
|
+
if (relayEnabled !== false && firstError instanceof MediaRelayError) {
|
|
526
|
+
logger.info(
|
|
527
|
+
`[MessageForward] relay failed, retrying without relay: ${node.Platform}`
|
|
528
|
+
);
|
|
529
|
+
withTimeout(
|
|
530
|
+
MessageSendWithDecorator(ctx2, node, session, MsgDecoratorNoRelay)
|
|
531
|
+
).catch((secondError) => {
|
|
532
|
+
logger.error(
|
|
533
|
+
`ERROR:<MessageSendDirect ${node.Platform}> ctx=${ctx2} ${sessionTypeArray(session)} ${secondError}`
|
|
534
|
+
);
|
|
535
|
+
sendDegraded(reasonFromError(secondError));
|
|
536
|
+
});
|
|
537
|
+
} else {
|
|
538
|
+
sendDegraded(reasonFromError(firstError));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
);
|
|
510
542
|
}
|
|
511
543
|
async function MessageDelete(ctx2, msg) {
|
|
512
544
|
if (!botExistsCheck(ctx2, { Platform: msg.platform, BotID: msg.bot, Guild: msg.guild })) {
|
|
@@ -548,7 +580,7 @@ function defaultDecorator({ head, content }) {
|
|
|
548
580
|
return msg;
|
|
549
581
|
}
|
|
550
582
|
function defaultMiddleware(session) {
|
|
551
|
-
|
|
583
|
+
const head = [(0, import_koishi6.h)("span", renderTemplate(defaultPrefix, session))];
|
|
552
584
|
if (defaultPrefixNewline) {
|
|
553
585
|
head.push((0, import_koishi6.h)("br"));
|
|
554
586
|
}
|
|
@@ -572,24 +604,21 @@ function msgMiddleCacheFind(uuid) {
|
|
|
572
604
|
return null;
|
|
573
605
|
}
|
|
574
606
|
function MsgToMiddleware(session) {
|
|
575
|
-
|
|
576
|
-
let _platform_in = decorators_exports[session.platform];
|
|
607
|
+
const _platform_in = decorators_exports[session.platform];
|
|
577
608
|
if (_platform_in && typeof _platform_in.Middleware === "function") {
|
|
578
|
-
|
|
579
|
-
} else {
|
|
580
|
-
elems = defaultMiddleware(session);
|
|
609
|
+
return _platform_in.Middleware(session);
|
|
581
610
|
}
|
|
582
|
-
return
|
|
611
|
+
return defaultMiddleware(session);
|
|
583
612
|
}
|
|
584
613
|
async function MsgMiddlewareCache(session) {
|
|
585
|
-
|
|
614
|
+
const elems = MsgToMiddleware(session);
|
|
586
615
|
msgMiddleCacheAppend({ UUID: MsgUUIDFromSession(session), msg: elems });
|
|
587
616
|
logger.debug(`[msgMiddleCache] CACHED`);
|
|
588
617
|
}
|
|
589
618
|
async function MsgDecorator(session, node) {
|
|
590
619
|
let elems;
|
|
591
|
-
|
|
592
|
-
|
|
620
|
+
const _platform_out = decorators_exports[node.Platform];
|
|
621
|
+
const elemCache = msgMiddleCacheFind(MsgUUIDFromSession(session));
|
|
593
622
|
if (elemCache) {
|
|
594
623
|
logger.debug(`[msgMiddleCache] HIT`);
|
|
595
624
|
elems = elemCache;
|
|
@@ -610,9 +639,28 @@ async function MsgDecorator(session, node) {
|
|
|
610
639
|
return defaultDecorator(elems);
|
|
611
640
|
}
|
|
612
641
|
}
|
|
642
|
+
async function MsgDecoratorNoRelay(session, node) {
|
|
643
|
+
let elems;
|
|
644
|
+
const _platform_out = decorators_exports[node.Platform];
|
|
645
|
+
const elemCache = msgMiddleCacheFind(MsgUUIDFromSession(session));
|
|
646
|
+
if (elemCache) {
|
|
647
|
+
elems = elemCache;
|
|
648
|
+
} else {
|
|
649
|
+
elems = MsgToMiddleware(session);
|
|
650
|
+
}
|
|
651
|
+
for (const fn of localDecorators) {
|
|
652
|
+
elems = await fn(session, node, elems);
|
|
653
|
+
}
|
|
654
|
+
logger.debug(`[MsgDecoratorNoRelay] fallback to direct forward`);
|
|
655
|
+
if (_platform_out && typeof _platform_out.Decorator === "function") {
|
|
656
|
+
return _platform_out.Decorator(elems);
|
|
657
|
+
} else {
|
|
658
|
+
return defaultDecorator(elems);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
613
661
|
function defaultDecoratorFallback({ head, content }, reason) {
|
|
614
662
|
let msg = [];
|
|
615
|
-
|
|
663
|
+
const newContent = [];
|
|
616
664
|
newContent.push((0, import_koishi6.h)("span", reason || defaultFallback));
|
|
617
665
|
for (const key in content) {
|
|
618
666
|
if (["img", "audio", "video", "file"].includes(content[key].type)) {
|
|
@@ -625,16 +673,14 @@ function defaultDecoratorFallback({ head, content }, reason) {
|
|
|
625
673
|
return msg;
|
|
626
674
|
}
|
|
627
675
|
async function MsgDecoratorFallback(session, node) {
|
|
628
|
-
let elems =
|
|
629
|
-
elems = defaultMiddleware(session);
|
|
676
|
+
let elems = defaultMiddleware(session);
|
|
630
677
|
for (const fn of localDecorators) {
|
|
631
678
|
elems = await fn(session, node, elems);
|
|
632
679
|
}
|
|
633
680
|
return defaultDecoratorFallback(elems);
|
|
634
681
|
}
|
|
635
682
|
async function MsgDecoratorFallbackReason(session, node, reason) {
|
|
636
|
-
let elems =
|
|
637
|
-
elems = defaultMiddleware(session);
|
|
683
|
+
let elems = defaultMiddleware(session);
|
|
638
684
|
for (const fn of localDecorators) {
|
|
639
685
|
elems = await fn(session, node, elems);
|
|
640
686
|
}
|
|
@@ -642,7 +688,7 @@ async function MsgDecoratorFallbackReason(session, node, reason) {
|
|
|
642
688
|
}
|
|
643
689
|
async function atTranslator(session, _, { head, content }) {
|
|
644
690
|
const newMsg = await new Promise((resolve) => {
|
|
645
|
-
|
|
691
|
+
const newContent = [];
|
|
646
692
|
for (const key in content) {
|
|
647
693
|
const element = content[key];
|
|
648
694
|
if (element.type === "at") {
|
|
@@ -666,9 +712,9 @@ async function quoteTranslator(session, node, { head, content }) {
|
|
|
666
712
|
const key = session.channelId + ":" + session.quote.id;
|
|
667
713
|
const cache = await msgCacheFindByKey(key);
|
|
668
714
|
if (cache) {
|
|
669
|
-
|
|
715
|
+
const msgid = await msgCacheGetLocalIDByUUID(node, cache.uuid);
|
|
670
716
|
if (msgid) {
|
|
671
|
-
|
|
717
|
+
const newHead = [(0, import_koishi6.h)("quote", { id: msgid })].concat(head);
|
|
672
718
|
return { head: newHead, content };
|
|
673
719
|
} else {
|
|
674
720
|
logger.error(`[msgCacheGetLocalIDByUUID] ${cache.uuid} not found`);
|
|
@@ -712,7 +758,7 @@ function apply(ctx2, cfg) {
|
|
|
712
758
|
session.platform,
|
|
713
759
|
session.channelId + ":" + session.messageId
|
|
714
760
|
);
|
|
715
|
-
|
|
761
|
+
const uuid = MsgUUIDFromSession(session);
|
|
716
762
|
msgCache({
|
|
717
763
|
platform: session.platform,
|
|
718
764
|
bot: group.Nodes[k].BotID,
|
|
@@ -732,7 +778,13 @@ function apply(ctx2, cfg) {
|
|
|
732
778
|
const group = cfg.ForwardGroups[hitGroup[g]];
|
|
733
779
|
for (const k in group.Nodes) {
|
|
734
780
|
if (group.Nodes[k].Guild !== session.channelId) {
|
|
735
|
-
MessageForward(
|
|
781
|
+
MessageForward(
|
|
782
|
+
ctx2,
|
|
783
|
+
group.Nodes[k],
|
|
784
|
+
session,
|
|
785
|
+
cfg.ForwardTimeoutSec,
|
|
786
|
+
cfg.MediaRelay.Enabled
|
|
787
|
+
);
|
|
736
788
|
}
|
|
737
789
|
}
|
|
738
790
|
}
|
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.0",
|
|
4
|
+
"version": "1.4.1-alpha.0",
|
|
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",
|