mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
67 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
743c5b8196 | ||
![]() |
5e62abea57 | ||
![]() |
6bfc545582 | ||
![]() |
411108a2d2 | ||
![]() |
308a6fa9e4 | ||
![]() |
2dc7b785d0 | ||
![]() |
0e69e9e839 | ||
![]() |
b83229b5da | ||
![]() |
6f053f5f7d | ||
![]() |
c3dc53eaaf | ||
![]() |
ffdc34cfe2 | ||
![]() |
4825a0e341 | ||
![]() |
95a00d7f35 | ||
![]() |
d885bab426 | ||
![]() |
e2a6a0bc02 | ||
![]() |
ff7d8609ce | ||
![]() |
7507b90e03 | ||
![]() |
2b226a4b27 | ||
![]() |
8b0232c4fe | ||
![]() |
0728ee9ad6 | ||
![]() |
8c6f04d0bc | ||
![]() |
c67fad789e | ||
![]() |
4072339d70 | ||
![]() |
3a244f5804 | ||
![]() |
f12cf59137 | ||
![]() |
c76f556a11 | ||
![]() |
e0f3d07b98 | ||
![]() |
378d85dc67 | ||
![]() |
875e91fc0e | ||
![]() |
15f7cd9814 | ||
![]() |
1eb5cd6237 | ||
![]() |
ad2f843c8f | ||
![]() |
8e550e216e | ||
![]() |
9f07b07c82 | ||
![]() |
0be6effc32 | ||
![]() |
7ab6a10fc9 | ||
![]() |
fb09af0e64 | ||
![]() |
0d99d30b2d | ||
![]() |
0000ec8b5b | ||
![]() |
0085bd8a1f | ||
![]() |
617139dfa4 | ||
![]() |
4eb4a612d0 | ||
![]() |
cda5e784f6 | ||
![]() |
d93a280ab3 | ||
![]() |
f7e2b3a4a7 | ||
![]() |
39d9c8fa74 | ||
![]() |
8823895a03 | ||
![]() |
b44a9e696c | ||
![]() |
cf28a3dc17 | ||
![]() |
7416e6caf6 | ||
![]() |
90f6896f3c | ||
![]() |
eebcd0700d | ||
![]() |
133eee0c66 | ||
![]() |
640fb75f74 | ||
![]() |
51dcc1add6 | ||
![]() |
730c928f91 | ||
![]() |
c3b7e111b9 | ||
![]() |
1874e48925 | ||
![]() |
e7a082c91c | ||
![]() |
5d4f45407e | ||
![]() |
17c37ec32f | ||
![]() |
b5f8140c79 | ||
![]() |
63f746c237 | ||
![]() |
dac6709f27 | ||
![]() |
2f08b72d69 | ||
![]() |
0081000ef0 | ||
![]() |
ad4d6a1070 |
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
@@ -127,6 +127,10 @@ jobs:
|
|||||||
zip -q -r NapCat.Framework.Windows.Once.zip *
|
zip -q -r NapCat.Framework.Windows.Once.zip *
|
||||||
cd ..
|
cd ..
|
||||||
mv ./NapCat.Framework.Windows.Once/NapCat.Framework.Windows.Once.zip ./
|
mv ./NapCat.Framework.Windows.Once/NapCat.Framework.Windows.Once.zip ./
|
||||||
|
mv ./external/napcat.packet.arm64 ./
|
||||||
|
mv ./external/napcat.packet.exe ./
|
||||||
|
mv ./external/napcat.packet.linux ./
|
||||||
|
mv ./external/napcat.packet.production.py ./
|
||||||
- name: Extract version from tag
|
- name: Extract version from tag
|
||||||
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
|
||||||
|
|
||||||
@@ -143,4 +147,8 @@ jobs:
|
|||||||
NapCat.Framework.zip
|
NapCat.Framework.zip
|
||||||
NapCat.Shell.zip
|
NapCat.Shell.zip
|
||||||
NapCat.Framework.Windows.Once.zip
|
NapCat.Framework.Windows.Once.zip
|
||||||
|
napcat.packet.arm64
|
||||||
|
napcat.packet.exe
|
||||||
|
napcat.packet.linux
|
||||||
|
napcat.packet.production.py
|
||||||
draft: true
|
draft: true
|
||||||
|
BIN
external/packet/napcat.packet.arm64
vendored
Normal file
BIN
external/packet/napcat.packet.arm64
vendored
Normal file
Binary file not shown.
BIN
external/packet/napcat.packet.exe
vendored
Normal file
BIN
external/packet/napcat.packet.exe
vendored
Normal file
Binary file not shown.
BIN
external/packet/napcat.packet.linux
vendored
Normal file
BIN
external/packet/napcat.packet.linux
vendored
Normal file
Binary file not shown.
102
external/packet/napcat.packet.production.py
vendored
Normal file
102
external/packet/napcat.packet.production.py
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
logo.png
BIN
logo.png
Binary file not shown.
Before Width: | Height: | Size: 208 KiB After Width: | Height: | Size: 335 KiB |
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "3.1.6",
|
"version": "3.3.16",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "3.1.6",
|
"version": "3.3.16",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:framework": "vite build --mode framework",
|
"build:framework": "vite build --mode framework",
|
||||||
"build:shell": "vite build --mode shell",
|
"build:shell": "vite build --mode shell",
|
||||||
|
@@ -4,16 +4,27 @@ const process = require("process");
|
|||||||
console.log("[NapCat] [CheckVersion] 开始检测当前仓库版本...");
|
console.log("[NapCat] [CheckVersion] 开始检测当前仓库版本...");
|
||||||
try {
|
try {
|
||||||
const packageJson = require("../package.json");
|
const packageJson = require("../package.json");
|
||||||
|
const manifsetJson = require("../manifest.json");
|
||||||
|
|
||||||
const currentVersion = packageJson.version;
|
const currentVersion = packageJson.version;
|
||||||
const targetVersion = process.env.VERSION;
|
const targetVersion = process.env.VERSION;
|
||||||
|
|
||||||
|
const manifestCurrentVersion = manifsetJson.version;
|
||||||
|
const manifestTargetVersion = process.env.VERSION;
|
||||||
|
|
||||||
console.log("[NapCat] [CheckVersion] currentVersion:", currentVersion, "targetVersion:", targetVersion);
|
console.log("[NapCat] [CheckVersion] currentVersion:", currentVersion, "targetVersion:", targetVersion);
|
||||||
|
console.log("[NapCat] [CheckVersion] manifestCurrentVersion:", manifestCurrentVersion, "manifestTargetVersion:", manifestTargetVersion);
|
||||||
|
|
||||||
// 验证 targetVersion 格式
|
// 验证 targetVersion 格式
|
||||||
if (!targetVersion || typeof targetVersion !== 'string') {
|
if (!targetVersion || typeof targetVersion !== 'string') {
|
||||||
console.log("[NapCat] [CheckVersion] 目标版本格式不正确或未设置!");
|
console.log("[NapCat] [CheckVersion] 目标版本格式不正确或未设置!");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 验证 manifestTargetVersion 格式
|
||||||
|
if (!manifestTargetVersion || typeof manifestTargetVersion !== 'string') {
|
||||||
|
console.log("[NapCat] [CheckVersion] manifest目标版本格式不正确或未设置!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// 写入脚本文件的统一函数
|
// 写入脚本文件的统一函数
|
||||||
const writeScriptToFile = (content) => {
|
const writeScriptToFile = (content) => {
|
||||||
@@ -21,7 +32,7 @@ try {
|
|||||||
console.log("[NapCat] [CheckVersion] checkVersion.sh 文件已更新。");
|
console.log("[NapCat] [CheckVersion] checkVersion.sh 文件已更新。");
|
||||||
};
|
};
|
||||||
|
|
||||||
if (currentVersion === targetVersion) {
|
if (currentVersion === targetVersion && manifestCurrentVersion === manifestTargetVersion) {
|
||||||
// 不需要更新版本,写入一个简单的脚本
|
// 不需要更新版本,写入一个简单的脚本
|
||||||
const simpleScript = "#!/bin/bash\necho \"CheckVersion Is Done\"";
|
const simpleScript = "#!/bin/bash\necho \"CheckVersion Is Done\"";
|
||||||
writeScriptToFile(simpleScript);
|
writeScriptToFile(simpleScript);
|
||||||
@@ -31,7 +42,10 @@ try {
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
git config --global user.email "bot@test.wumiao.wang"
|
git config --global user.email "bot@test.wumiao.wang"
|
||||||
git config --global user.name "Version"
|
git config --global user.name "Version"
|
||||||
sed -i "s/\\\"version\\\": \\\"${currentVersion}\\\"/\\\"version\\\": \\\"${targetVersion}\\\"/g" package.json
|
sed -i "s/\\"version\\": \\"${currentVersion}\\"/\\"version\\": \\"${targetVersion}\\"/g" package.json
|
||||||
|
sed -i "s/\\"version\\": \\"${manifestCurrentVersion}\\"/\\"version\\": \\"${targetVersion}\\"/g" manifest.json
|
||||||
|
sed -i "s/napCatVersion = '.*'/napCatVersion = '${targetVersion}'/g" ./src/common/version.ts
|
||||||
|
sed -i "s/SettingButton(\\"V.*\\", \\"napcat-update-button\\", \\"secondary\\")/SettingButton(\\"V${targetVersion}\\", \\"napcat-update-button\\", \\"secondary\\")/g" ./static/assets/renderer.js
|
||||||
git add .
|
git add .
|
||||||
git commit -m "chore:version change"
|
git commit -m "chore:version change"
|
||||||
git push -u origin main`;
|
git push -u origin main`;
|
||||||
|
@@ -55,10 +55,10 @@ export class ForwardMsgBuilder {
|
|||||||
const isGroupMsg = msg.some(m => m.isGroupMsg);
|
const isGroupMsg = msg.some(m => m.isGroupMsg);
|
||||||
if (!source) {
|
if (!source) {
|
||||||
source = isGroupMsg ? "群聊的聊天记录" :
|
source = isGroupMsg ? "群聊的聊天记录" :
|
||||||
msg.length
|
msg.length
|
||||||
? Array.from(new Set(msg.map(m => m.senderName)))
|
? Array.from(new Set(msg.slice(0, 4).map(m => m.senderName)))
|
||||||
.join('和') + '的聊天记录'
|
.join('和') + '的聊天记录'
|
||||||
: '聊天记录';
|
: '聊天记录';
|
||||||
}
|
}
|
||||||
if (!news) {
|
if (!news) {
|
||||||
news = msg.length === 0 ? [{
|
news = msg.length === 0 ? [{
|
||||||
|
@@ -239,3 +239,9 @@ export function calcQQLevel(level?: QQLevel) {
|
|||||||
const { crownNum, sunNum, moonNum, starNum } = level;
|
const { crownNum, sunNum, moonNum, starNum } = level;
|
||||||
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
return crownNum * 64 + sunNum * 16 + moonNum * 4 + starNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function stringifyWithBigInt(obj: any) {
|
||||||
|
return JSON.stringify(obj, (key, value) =>
|
||||||
|
typeof value === 'bigint' ? value.toString() : value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '3.1.6';
|
export const napCatVersion = '3.3.12';
|
||||||
|
@@ -6,6 +6,7 @@ import {
|
|||||||
Peer,
|
Peer,
|
||||||
PicElement,
|
PicElement,
|
||||||
PicType,
|
PicType,
|
||||||
|
RawMessage,
|
||||||
SendFileElement,
|
SendFileElement,
|
||||||
SendPicElement,
|
SendPicElement,
|
||||||
SendPttElement,
|
SendPttElement,
|
||||||
@@ -238,7 +239,7 @@ export class NTQQFileApi {
|
|||||||
fileName: fileName,
|
fileName: fileName,
|
||||||
filePath: path,
|
filePath: path,
|
||||||
md5HexStr: md5,
|
md5HexStr: md5,
|
||||||
fileSize: fileSize,
|
fileSize: fileSize.toString(),
|
||||||
duration: duration ?? 1,
|
duration: duration ?? 1,
|
||||||
formatType: 1,
|
formatType: 1,
|
||||||
voiceType: 1,
|
voiceType: 1,
|
||||||
@@ -267,6 +268,53 @@ export class NTQQFileApi {
|
|||||||
return fileTransNotifyInfo.filePath;
|
return fileTransNotifyInfo.filePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async downloadRawMsgMedia(msg: RawMessage[]) {
|
||||||
|
const res = await Promise.all(
|
||||||
|
msg.map(m =>
|
||||||
|
Promise.all(
|
||||||
|
m.elements
|
||||||
|
.filter(element =>
|
||||||
|
element.elementType === ElementType.PIC ||
|
||||||
|
element.elementType === ElementType.VIDEO ||
|
||||||
|
element.elementType === ElementType.PTT ||
|
||||||
|
element.elementType === ElementType.FILE
|
||||||
|
)
|
||||||
|
.map(element =>
|
||||||
|
this.downloadMedia(m.msgId, m.chatType, m.peerUid, element.elementId, '', '', 1000 * 60 * 2, true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
msg.forEach((m, msgIndex) => {
|
||||||
|
const elementResults = res[msgIndex];
|
||||||
|
let elementIndex = 0;
|
||||||
|
m.elements.forEach(element => {
|
||||||
|
if (
|
||||||
|
element.elementType === ElementType.PIC ||
|
||||||
|
element.elementType === ElementType.VIDEO ||
|
||||||
|
element.elementType === ElementType.PTT ||
|
||||||
|
element.elementType === ElementType.FILE
|
||||||
|
) {
|
||||||
|
switch (element.elementType) {
|
||||||
|
case ElementType.PIC:
|
||||||
|
element.picElement!.sourcePath = elementResults[elementIndex];
|
||||||
|
break;
|
||||||
|
case ElementType.VIDEO:
|
||||||
|
element.videoElement!.filePath = elementResults[elementIndex];
|
||||||
|
break;
|
||||||
|
case ElementType.PTT:
|
||||||
|
element.pttElement!.filePath = elementResults[elementIndex];
|
||||||
|
break;
|
||||||
|
case ElementType.FILE:
|
||||||
|
element.fileElement!.filePath = elementResults[elementIndex];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
elementIndex++;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
|
async downloadMedia(msgId: string, chatType: ChatType, peerUid: string, elementId: string, thumbPath: string, sourcePath: string, timeout = 1000 * 60 * 2, force: boolean = false) {
|
||||||
// 用于下载收到的消息中的图片等
|
// 用于下载收到的消息中的图片等
|
||||||
if (sourcePath && fs.existsSync(sourcePath)) {
|
if (sourcePath && fs.existsSync(sourcePath)) {
|
||||||
@@ -296,7 +344,7 @@ export class NTQQFileApi {
|
|||||||
filePath: thumbPath,
|
filePath: thumbPath,
|
||||||
}],
|
}],
|
||||||
() => true,
|
() => true,
|
||||||
(arg) => arg.msgId === msgId,
|
(arg) => arg.msgElementId === elementId && arg.msgId === msgId,
|
||||||
1,
|
1,
|
||||||
timeout,
|
timeout,
|
||||||
);
|
);
|
||||||
@@ -378,8 +426,8 @@ export class NTQQFileApi {
|
|||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
if (this.core.apis.PacketApi.available) {
|
if (this.core.apis.PacketApi.available) {
|
||||||
let rkey_expired_private = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
|
const rkey_expired_private = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
|
||||||
let rkey_expired_group = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
|
const rkey_expired_group = !this.packetRkey || this.packetRkey[0].time + Number(this.packetRkey[0].ttl) < Date.now() / 1000;
|
||||||
if (rkey_expired_private || rkey_expired_group) {
|
if (rkey_expired_private || rkey_expired_group) {
|
||||||
this.packetRkey = await this.core.apis.PacketApi.sendRkeyPacket();
|
this.packetRkey = await this.core.apis.PacketApi.sendRkeyPacket();
|
||||||
}
|
}
|
||||||
|
@@ -34,7 +34,13 @@ export class NTQQFriendApi {
|
|||||||
data.forEach((value) => retMap.set(value.uin!, value.uid!));
|
data.forEach((value) => retMap.set(value.uin!, value.uid!));
|
||||||
return retMap;
|
return retMap;
|
||||||
}
|
}
|
||||||
|
async delBuudy(uid: string, tempBlock = false, tempBothDel = false) {
|
||||||
|
return this.context.session.getBuddyService().delBuddy({
|
||||||
|
friendUid: uid,
|
||||||
|
tempBlock: tempBlock,
|
||||||
|
tempBothDel: tempBothDel
|
||||||
|
});
|
||||||
|
}
|
||||||
async getBuddyV2ExWithCate(refresh = false) {
|
async getBuddyV2ExWithCate(refresh = false) {
|
||||||
const categoryMap: Map<string, any> = new Map();
|
const categoryMap: Map<string, any> = new Map();
|
||||||
const buddyService = this.context.session.getBuddyService();
|
const buddyService = this.context.session.getBuddyService();
|
||||||
|
@@ -316,18 +316,42 @@ export class NTQQGroupApi {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupMembersV2(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
async tryGetGroupMembersV2(modeListener = false, groupQQ: string, num = 30, timeout = 100): Promise<{
|
||||||
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow');
|
infos: Map<string, GroupMember>;
|
||||||
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', 1, 2000, (params) => params.sceneId === sceneId)
|
finish: boolean;
|
||||||
.catch();
|
hasNext: boolean | undefined;
|
||||||
const result = await this.context.session.getGroupService().getNextMemberList(sceneId!, undefined, num);
|
}>{
|
||||||
|
const sceneId = this.context.session.getGroupService().createMemberListScene(groupQQ, 'groupMemberList_MainWindow_1');
|
||||||
|
const once = this.core.eventWrapper.registerListen('NodeIKernelGroupListener/onMemberListChange', 0, timeout, (params) => params.sceneId === sceneId)
|
||||||
|
.catch(() => {});
|
||||||
|
const result = await this.context.session.getGroupService().getNextMemberList(sceneId, undefined, num);
|
||||||
if (result.errCode !== 0) {
|
if (result.errCode !== 0) {
|
||||||
throw new Error('获取群成员列表出错,' + result.errMsg);
|
throw new Error('获取群成员列表出错,' + result.errMsg);
|
||||||
}
|
}
|
||||||
if (result.result.infos.size === 0) {
|
let resMode2;
|
||||||
return (await once)[0].infos;
|
if (modeListener) {
|
||||||
|
const ret = (await once)?.[0];
|
||||||
|
if (ret) {
|
||||||
|
resMode2 = ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return result.result.infos;
|
this.context.session.getGroupService().destroyMemberListScene(sceneId);
|
||||||
|
return {
|
||||||
|
infos: resMode2?.infos || result.result.infos,
|
||||||
|
finish: result.result.finish,
|
||||||
|
hasNext: resMode2?.hasNext,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async getGroupMembersV2(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||||
|
let res = await this.tryGetGroupMembersV2(true, groupQQ);
|
||||||
|
if (res.hasNext || !res.finish || res.infos.size === 0) {
|
||||||
|
res = await this.tryGetGroupMembersV2(false, groupQQ, num);
|
||||||
|
}
|
||||||
|
if ((res.infos.size === 0 || res.infos.size === 30) && res.finish) {
|
||||||
|
res = await this.tryGetGroupMembersV2(true, groupQQ, num);
|
||||||
|
}
|
||||||
|
return res.infos;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
async getGroupMembers(groupQQ: string, num = 3000): Promise<Map<string, GroupMember>> {
|
||||||
@@ -425,7 +449,7 @@ export class NTQQGroupApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getGroupRemainAtTimes(GroupCode: string) {
|
async getGroupRemainAtTimes(GroupCode: string) {
|
||||||
this.context.session.getGroupService().getGroupRemainAtTimes(GroupCode);
|
return this.context.session.getGroupService().getGroupRemainAtTimes(GroupCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
async getMemberExtInfo(groupCode: string, uin: string) {
|
async getMemberExtInfo(groupCode: string, uin: string) {
|
||||||
|
@@ -82,6 +82,18 @@ export class NTQQMsgApi {
|
|||||||
pageLimit: 1,
|
pageLimit: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async queryMsgsWithFilterExWithSeqV3(peer: Peer, msgSeq: string, SendersUid: string[]) {
|
||||||
|
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||||
|
chatInfo: peer,
|
||||||
|
filterMsgType: [],
|
||||||
|
filterSendersUid: SendersUid,
|
||||||
|
filterMsgToTime: '0',
|
||||||
|
filterMsgFromTime: '0',
|
||||||
|
isReverseOrder: false,
|
||||||
|
isIncludeCurrent: true,
|
||||||
|
pageLimit: 1,
|
||||||
|
});
|
||||||
|
}
|
||||||
async queryFirstMsgBySeq(peer: Peer, msgSeq: string) {
|
async queryFirstMsgBySeq(peer: Peer, msgSeq: string) {
|
||||||
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
|
||||||
chatInfo: peer,
|
chatInfo: peer,
|
||||||
|
@@ -3,7 +3,7 @@ import { ChatType, InstanceContext, NapCatCore } from '..';
|
|||||||
import offset from '@/core/external/offset.json';
|
import offset from '@/core/external/offset.json';
|
||||||
import { PacketClient, RecvPacketData } from '@/core/packet/client';
|
import { PacketClient, RecvPacketData } from '@/core/packet/client';
|
||||||
import { PacketSession } from "@/core/packet/session";
|
import { PacketSession } from "@/core/packet/session";
|
||||||
import {OidbPacket, PacketHexStr} from "@/core/packet/packer";
|
import { OidbPacket, PacketHexStr } from "@/core/packet/packer";
|
||||||
import { NapProtoMsg } from '@/core/packet/proto/NapProto';
|
import { NapProtoMsg } from '@/core/packet/proto/NapProto';
|
||||||
import { OidbSvcTrpcTcp0X9067_202_Rsp_Body } from '@/core/packet/proto/oidb/Oidb.0x9067_202';
|
import { OidbSvcTrpcTcp0X9067_202_Rsp_Body } from '@/core/packet/proto/oidb/Oidb.0x9067_202';
|
||||||
import { OidbSvcTrpcTcpBase, OidbSvcTrpcTcpBaseRsp } from '@/core/packet/proto/oidb/OidbBase';
|
import { OidbSvcTrpcTcpBase, OidbSvcTrpcTcpBaseRsp } from '@/core/packet/proto/oidb/OidbBase';
|
||||||
@@ -49,7 +49,7 @@ export class NTQQPacketApi {
|
|||||||
.then()
|
.then()
|
||||||
.catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
.catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||||
} else {
|
} else {
|
||||||
this.core.context.logger.logWarn('PacketServer is not set, will not init NapCat.Packet!');
|
this.core.context.logger.logWarn('PacketServer未配置,NapCat.Packet将不会加载!');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,7 +62,10 @@ export class NTQQPacketApi {
|
|||||||
this.qqVersion = qqversion;
|
this.qqVersion = qqversion;
|
||||||
const offsetTable: OffsetType = offset;
|
const offsetTable: OffsetType = offset;
|
||||||
const table = offsetTable[qqversion + '-' + os.arch()];
|
const table = offsetTable[qqversion + '-' + os.arch()];
|
||||||
if (!table) return false;
|
if (!table) {
|
||||||
|
this.logger.logError('PacketServer Offset table not found for QQVersion: ', qqversion + '-' + os.arch());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
const url = 'ws://' + this.serverUrl + '/ws';
|
const url = 'ws://' + this.serverUrl + '/ws';
|
||||||
this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core));
|
this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core));
|
||||||
const cb = () => {
|
const cb = () => {
|
||||||
@@ -103,7 +106,7 @@ export class NTQQPacketApi {
|
|||||||
let status = 0;
|
let status = 0;
|
||||||
try {
|
try {
|
||||||
const packet = this.packetSession?.packer.packStatusPacket(uin);
|
const packet = this.packetSession?.packer.packStatusPacket(uin);
|
||||||
const ret = await this.sendOidbPacket( packet!, true);
|
const ret = await this.sendOidbPacket(packet!, true);
|
||||||
const data = Buffer.from(ret.hex_data, 'hex');
|
const data = Buffer.from(ret.hex_data, 'hex');
|
||||||
const ext = new NapProtoMsg(OidbSvcTrpcTcp0XFE1_2RSP).decode(new NapProtoMsg(OidbSvcTrpcTcpBase).decode(data).body).data.status.value;
|
const ext = new NapProtoMsg(OidbSvcTrpcTcp0XFE1_2RSP).decode(new NapProtoMsg(OidbSvcTrpcTcpBase).decode(data).body).data.status.value;
|
||||||
// ext & 0xff00 + ext >> 16 & 0xff
|
// ext & 0xff00 + ext >> 16 & 0xff
|
||||||
@@ -146,7 +149,7 @@ export class NTQQPacketApi {
|
|||||||
peerUid: groupUin ? String(groupUin) : this.core.selfInfo.uid
|
peerUid: groupUin ? String(groupUin) : this.core.selfInfo.uid
|
||||||
}, e));
|
}, e));
|
||||||
}
|
}
|
||||||
if (e instanceof PacketMsgFileElement){
|
if (e instanceof PacketMsgFileElement) {
|
||||||
reqList.push(this.packetSession?.highwaySession.uploadFile({
|
reqList.push(this.packetSession?.highwaySession.uploadFile({
|
||||||
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
|
||||||
peerUid: groupUin ? String(groupUin) : this.core.selfInfo.uid
|
peerUid: groupUin ? String(groupUin) : this.core.selfInfo.uid
|
||||||
@@ -155,10 +158,10 @@ export class NTQQPacketApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
const res = await Promise.allSettled(reqList);
|
const res = await Promise.allSettled(reqList);
|
||||||
this.logger.log(`上传资源${res.length}个, 失败${res.filter(r => r.status === 'rejected').length}个`);
|
this.logger.log(`上传资源${res.length}个,失败${res.filter(r => r.status === 'rejected').length}个`);
|
||||||
res.forEach((result, index) => {
|
res.forEach((result, index) => {
|
||||||
if (result.status === 'rejected') {
|
if (result.status === 'rejected') {
|
||||||
this.logger.logError(`第${index + 1}个失败:${result.reason}`);
|
this.logger.logError(`上传第${index + 1}个资源失败:${result.reason}`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@@ -27,94 +27,70 @@ export interface GetFileListParam {
|
|||||||
|
|
||||||
export enum ElementType {
|
export enum ElementType {
|
||||||
UNKNOWN = 0,
|
UNKNOWN = 0,
|
||||||
|
|
||||||
TEXT = 1,
|
TEXT = 1,
|
||||||
|
|
||||||
PIC = 2,
|
PIC = 2,
|
||||||
|
|
||||||
FILE = 3,
|
FILE = 3,
|
||||||
|
|
||||||
PTT = 4,
|
PTT = 4,
|
||||||
|
|
||||||
VIDEO = 5,
|
VIDEO = 5,
|
||||||
|
|
||||||
FACE = 6,
|
FACE = 6,
|
||||||
|
|
||||||
REPLY = 7,
|
REPLY = 7,
|
||||||
|
GreyTip = 8, // “小灰条”,包括拍一拍 (Poke)、撤回提示等
|
||||||
WALLET = 9,
|
WALLET = 9,
|
||||||
|
|
||||||
/**
|
|
||||||
* “小灰条”,包括拍一拍 (Poke)、撤回提示等
|
|
||||||
*/
|
|
||||||
GreyTip = 8,
|
|
||||||
|
|
||||||
ARK = 10,
|
ARK = 10,
|
||||||
|
|
||||||
MFACE = 11,
|
MFACE = 11,
|
||||||
|
|
||||||
LIVEGIFT = 12,
|
LIVEGIFT = 12,
|
||||||
|
|
||||||
STRUCTLONGMSG = 13,
|
STRUCTLONGMSG = 13,
|
||||||
|
|
||||||
MARKDOWN = 14,
|
MARKDOWN = 14,
|
||||||
|
|
||||||
GIPHY = 15,
|
GIPHY = 15,
|
||||||
|
|
||||||
MULTIFORWARD = 16,
|
MULTIFORWARD = 16,
|
||||||
|
|
||||||
INLINEKEYBOARD = 17,
|
INLINEKEYBOARD = 17,
|
||||||
|
|
||||||
INTEXTGIFT = 18,
|
INTEXTGIFT = 18,
|
||||||
|
|
||||||
CALENDAR = 19,
|
CALENDAR = 19,
|
||||||
|
|
||||||
YOLOGAMERESULT = 20,
|
YOLOGAMERESULT = 20,
|
||||||
|
|
||||||
AVRECORD = 21,
|
AVRECORD = 21,
|
||||||
|
|
||||||
FEED = 22,
|
FEED = 22,
|
||||||
|
|
||||||
TOFURECORD = 23,
|
TOFURECORD = 23,
|
||||||
|
|
||||||
ACEBUBBLE = 24,
|
ACEBUBBLE = 24,
|
||||||
|
|
||||||
ACTIVITY = 25,
|
ACTIVITY = 25,
|
||||||
|
|
||||||
TOFU = 26,
|
TOFU = 26,
|
||||||
|
|
||||||
FACEBUBBLE = 27,
|
FACEBUBBLE = 27,
|
||||||
|
|
||||||
SHARELOCATION = 28,
|
SHARELOCATION = 28,
|
||||||
|
|
||||||
TASKTOPMSG = 29,
|
TASKTOPMSG = 29,
|
||||||
|
|
||||||
RECOMMENDEDMSG = 43,
|
RECOMMENDEDMSG = 43,
|
||||||
|
|
||||||
ACTIONBAR = 44
|
ACTIONBAR = 44
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ElementFullBase = Omit<MessageElement, 'elementType' | 'elementId' | 'extBufForUI'>;
|
||||||
|
|
||||||
|
type ElementBase<
|
||||||
|
K extends keyof ElementFullBase,
|
||||||
|
S extends Partial<{ [P in K]: keyof NonNullable<ElementFullBase[P]> | Array<keyof NonNullable<ElementFullBase[P]>> }> = {}
|
||||||
|
> = {
|
||||||
|
[P in K]:
|
||||||
|
S[P] extends Array<infer U>
|
||||||
|
? Pick<NonNullable<ElementFullBase[P]>, U & keyof NonNullable<ElementFullBase[P]>>
|
||||||
|
: S[P] extends keyof NonNullable<ElementFullBase[P]>
|
||||||
|
? Pick<NonNullable<ElementFullBase[P]>, S[P]>
|
||||||
|
: NonNullable<ElementFullBase[P]>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface SendElementBase<ET extends ElementType> {
|
||||||
|
elementType: ET;
|
||||||
|
elementId: string;
|
||||||
|
extBufForUI?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ActionBarElement {
|
export interface ActionBarElement {
|
||||||
rows: InlineKeyboardRow[];
|
rows: InlineKeyboardRow[];
|
||||||
botAppid: string;
|
botAppid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendActionBarElement {
|
|
||||||
elementType: ElementType.ACTIONBAR;
|
|
||||||
elementId: string;
|
|
||||||
actionBarElement: ActionBarElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RecommendedMsgElement {
|
export interface RecommendedMsgElement {
|
||||||
rows: InlineKeyboardRow[];
|
rows: InlineKeyboardRow[];
|
||||||
botAppid: string;
|
botAppid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendRecommendedMsgElement {
|
export type SendRecommendedMsgElement = SendElementBase<ElementType.RECOMMENDEDMSG> & ElementBase<'recommendedMsgElement'>;
|
||||||
elementType: ElementType.RECOMMENDEDMSG;
|
|
||||||
elementId: string;
|
|
||||||
recommendedMsgElement: RecommendedMsgElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InlineKeyboardButton {
|
export interface InlineKeyboardButton {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -171,11 +147,7 @@ export enum NTMsgType {
|
|||||||
KMSGTYPEWALLET = 10
|
KMSGTYPEWALLET = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendTaskTopMsgElement {
|
export type SendTaskTopMsgElement = SendElementBase<ElementType.TASKTOPMSG> & ElementBase<'taskTopMsgElement'>;
|
||||||
elementType: ElementType.TASKTOPMSG;
|
|
||||||
elementId: string;
|
|
||||||
taskTopMsgElement: TaskTopMsgElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TofuRecordElement {
|
export interface TofuRecordElement {
|
||||||
type: number;
|
type: number;
|
||||||
@@ -194,11 +166,7 @@ export interface TofuRecordElement {
|
|||||||
onscreennotify: boolean;
|
onscreennotify: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendTofuRecordElement {
|
export type SendTofuRecordElement = SendElementBase<ElementType.TOFURECORD> & ElementBase<'tofuRecordElement'>;
|
||||||
elementType: ElementType.TOFURECORD;
|
|
||||||
elementId: string;
|
|
||||||
tofuRecordElement: TofuRecordElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FaceBubbleElement {
|
export interface FaceBubbleElement {
|
||||||
faceCount: number;
|
faceCount: number;
|
||||||
@@ -216,12 +184,7 @@ export interface FaceBubbleElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendFaceBubbleElement {
|
export type SendFaceBubbleElement = SendElementBase<ElementType.FACEBUBBLE> & ElementBase<'faceBubbleElement'>;
|
||||||
elementType: ElementType.FACEBUBBLE;
|
|
||||||
elementId: string;
|
|
||||||
faceBubbleElement: FaceBubbleElement;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AvRecordElement {
|
export interface AvRecordElement {
|
||||||
type: number;
|
type: number;
|
||||||
@@ -232,11 +195,7 @@ export interface AvRecordElement {
|
|||||||
extraType: number;
|
extraType: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendavRecordElement {
|
export type SendAvRecordElement = SendElementBase<ElementType.AVRECORD> & ElementBase<'avRecordElement'>;
|
||||||
elementType: ElementType.AVRECORD;
|
|
||||||
elementId: string;
|
|
||||||
avRecordElement: AvRecordElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface YoloUserInfo {
|
export interface YoloUserInfo {
|
||||||
uid: string;
|
uid: string;
|
||||||
@@ -245,24 +204,13 @@ export interface YoloUserInfo {
|
|||||||
bizId: string;
|
bizId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendInlineKeyboardElement {
|
export type SendInlineKeyboardElement = SendElementBase<ElementType.INLINEKEYBOARD> & ElementBase<'inlineKeyboardElement'>;
|
||||||
elementType: ElementType.INLINEKEYBOARD;
|
|
||||||
elementId: string;
|
|
||||||
inlineKeyboardElement: {
|
|
||||||
rows: number;
|
|
||||||
botAppid: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface YoloGameResultElement {
|
export interface YoloGameResultElement {
|
||||||
UserInfo: YoloUserInfo[];
|
UserInfo: YoloUserInfo[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendYoloGameResultElement {
|
export type SendYoloGameResultElement = SendElementBase<ElementType.YOLOGAMERESULT> & ElementBase<'yoloGameResultElement'>;
|
||||||
elementType: ElementType.YOLOGAMERESULT;
|
|
||||||
yoloGameResultElement: YoloGameResultElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GiphyElement {
|
export interface GiphyElement {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -271,17 +219,9 @@ export interface GiphyElement {
|
|||||||
height: number;
|
height: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendGiphyElement {
|
export type SendGiphyElement = SendElementBase<ElementType.GIPHY> & ElementBase<'giphyElement'>;
|
||||||
elementType: ElementType.GIPHY;
|
|
||||||
elementId: string;
|
|
||||||
giphyElement: GiphyElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendWalletElement {
|
export type SendWalletElement = SendElementBase<ElementType.UNKNOWN> & ElementBase<'walletElement'>;
|
||||||
elementType: ElementType.UNKNOWN;//不做 设置位置
|
|
||||||
elementId: string;
|
|
||||||
walletElement: Record<string, never>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CalendarElement {
|
export interface CalendarElement {
|
||||||
summary: string;
|
summary: string;
|
||||||
@@ -291,49 +231,16 @@ export interface CalendarElement {
|
|||||||
schema: string;
|
schema: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendCalendarElement {
|
export type SendCalendarElement = SendElementBase<ElementType.CALENDAR> & ElementBase<'calendarElement'>;
|
||||||
elementType: ElementType.CALENDAR;
|
|
||||||
elementId: string;
|
|
||||||
calendarElement: CalendarElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendliveGiftElement {
|
export type SendLiveGiftElement = SendElementBase<ElementType.LIVEGIFT> & ElementBase<'liveGiftElement'>;
|
||||||
elementType: ElementType.LIVEGIFT;
|
|
||||||
elementId: string;
|
|
||||||
liveGiftElement: Record<string, never>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendTextElement {
|
export type SendTextElement = SendElementBase<ElementType.TEXT> & ElementBase<'textElement'>;
|
||||||
elementType: ElementType.TEXT;
|
|
||||||
elementId: string;
|
|
||||||
textElement: {
|
|
||||||
content: string;
|
|
||||||
atType: number;
|
|
||||||
atUid: string;
|
|
||||||
atTinyId: string;
|
|
||||||
atNtUid: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendPttElement {
|
export type SendPttElement = SendElementBase<ElementType.PTT> & ElementBase<'pttElement', {
|
||||||
elementType: ElementType.PTT;
|
pttElement: ['fileName', 'filePath', 'md5HexStr', 'fileSize', 'duration', 'formatType', 'voiceType',
|
||||||
elementId: string;
|
'voiceChangeType', 'canConvert2Text', 'waveAmplitudes', 'fileSubId', 'playState', 'autoConvertText']
|
||||||
pttElement: {
|
}>;
|
||||||
fileName: string;
|
|
||||||
filePath: string;
|
|
||||||
md5HexStr: string;
|
|
||||||
fileSize: number;
|
|
||||||
duration: number; // 单位是秒
|
|
||||||
formatType: number;
|
|
||||||
voiceType: number;
|
|
||||||
voiceChangeType: number;
|
|
||||||
canConvert2Text: boolean;
|
|
||||||
waveAmplitudes: number[];
|
|
||||||
fileSubId: string;
|
|
||||||
playState: number;
|
|
||||||
autoConvertText: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum PicType {
|
export enum PicType {
|
||||||
gif = 2000,
|
gif = 2000,
|
||||||
@@ -359,11 +266,7 @@ export enum NTMsgAtType {
|
|||||||
ATTYPEUNKNOWN = 0
|
ATTYPEUNKNOWN = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendPicElement {
|
export type SendPicElement = SendElementBase<ElementType.PIC> & ElementBase<'picElement'>;
|
||||||
elementType: ElementType.PIC;
|
|
||||||
elementId: string;
|
|
||||||
picElement: PicElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ReplyElement {
|
export interface ReplyElement {
|
||||||
sourceMsgIdInRecords?: string;
|
sourceMsgIdInRecords?: string;
|
||||||
@@ -375,53 +278,27 @@ export interface ReplyElement {
|
|||||||
replyMsgClientSeq?: string;
|
replyMsgClientSeq?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendReplyElement {
|
export type SendReplyElement = SendElementBase<ElementType.REPLY> & ElementBase<'replyElement'>;
|
||||||
elementType: ElementType.REPLY;
|
|
||||||
elementId: string;
|
|
||||||
replyElement: ReplyElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendFaceElement {
|
export type SendFaceElement = SendElementBase<ElementType.FACE> & ElementBase<'faceElement'>;
|
||||||
elementType: ElementType.FACE;
|
|
||||||
elementId: string;
|
|
||||||
faceElement: FaceElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendMarketFaceElement {
|
export type SendMarketFaceElement = SendElementBase<ElementType.MFACE> & ElementBase<'marketFaceElement'>;
|
||||||
elementType: ElementType.MFACE;
|
|
||||||
marketFaceElement: MarketFaceElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendStructLongMsgElement {
|
export type SendStructLongMsgElement = SendElementBase<ElementType.STRUCTLONGMSG> & ElementBase<'structLongMsgElement'>;
|
||||||
elementType: ElementType.STRUCTLONGMSG;
|
|
||||||
elementId: string;
|
|
||||||
structLongMsgElement: StructLongMsgElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StructLongMsgElement {
|
export interface StructLongMsgElement {
|
||||||
xmlContent: string;
|
xmlContent: string;
|
||||||
resId: string;
|
resId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendactionBarElement {
|
export type SendActionBarElement = SendElementBase<ElementType.ACTIONBAR> & ElementBase<'actionBarElement'>;
|
||||||
elementType: ElementType.ACTIONBAR;
|
|
||||||
elementId: string;
|
|
||||||
actionBarElement: {
|
|
||||||
rows: number;
|
|
||||||
botAppid: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ShareLocationElement {
|
export interface ShareLocationElement {
|
||||||
text: string;
|
text: string;
|
||||||
ext: string;
|
ext: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendShareLocationElement {
|
export type SendShareLocationElement = SendElementBase<ElementType.SHARELOCATION> & ElementBase<'shareLocationElement'>;
|
||||||
elementType: ElementType.SHARELOCATION;
|
|
||||||
elementId: string;
|
|
||||||
shareLocationElement?: ShareLocationElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface FileElement {
|
export interface FileElement {
|
||||||
fileMd5?: string;
|
fileMd5?: string;
|
||||||
@@ -441,29 +318,13 @@ export interface FileElement {
|
|||||||
fileBizId?: number;
|
fileBizId?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendFileElement {
|
export type SendFileElement = SendElementBase<ElementType.FILE> & ElementBase<'fileElement'>;
|
||||||
elementType: ElementType.FILE;
|
|
||||||
elementId: string;
|
|
||||||
fileElement: FileElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendVideoElement {
|
export type SendVideoElement = SendElementBase<ElementType.VIDEO> & ElementBase<'videoElement'>;
|
||||||
elementType: ElementType.VIDEO;
|
|
||||||
elementId: string;
|
|
||||||
videoElement: VideoElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendArkElement {
|
export type SendArkElement = SendElementBase<ElementType.ARK> & ElementBase<'arkElement'>;
|
||||||
elementType: ElementType.ARK;
|
|
||||||
elementId: string;
|
|
||||||
arkElement: ArkElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface SendMarkdownElement {
|
export type SendMarkdownElement = SendElementBase<ElementType.MARKDOWN> & ElementBase<'markdownElement'>;
|
||||||
elementType: ElementType.MARKDOWN;
|
|
||||||
elementId: string;
|
|
||||||
markdownElement: MarkdownElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type SendMessageElement = SendTextElement | SendPttElement |
|
export type SendMessageElement = SendTextElement | SendPttElement |
|
||||||
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
|
SendPicElement | SendReplyElement | SendFaceElement | SendMarketFaceElement | SendFileElement |
|
||||||
@@ -480,7 +341,7 @@ export interface TextElement {
|
|||||||
export interface MessageElement {
|
export interface MessageElement {
|
||||||
elementType: ElementType,
|
elementType: ElementType,
|
||||||
elementId: string,
|
elementId: string,
|
||||||
extBufForUI: string,//"0x",
|
extBufForUI?: string, //"0x",
|
||||||
textElement?: TextElement;
|
textElement?: TextElement;
|
||||||
faceElement?: FaceElement,
|
faceElement?: FaceElement,
|
||||||
marketFaceElement?: MarketFaceElement,
|
marketFaceElement?: MarketFaceElement,
|
||||||
@@ -509,7 +370,6 @@ export interface MessageElement {
|
|||||||
taskTopMsgElement?: TaskTopMsgElement,
|
taskTopMsgElement?: TaskTopMsgElement,
|
||||||
recommendedMsgElement?: RecommendedMsgElement,
|
recommendedMsgElement?: RecommendedMsgElement,
|
||||||
actionBarElement?: ActionBarElement
|
actionBarElement?: ActionBarElement
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AtType {
|
export enum AtType {
|
||||||
@@ -578,7 +438,7 @@ export interface PttElement {
|
|||||||
fileSize: string; // "4261"
|
fileSize: string; // "4261"
|
||||||
fileSubId: string; // "0"
|
fileSubId: string; // "0"
|
||||||
fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV"
|
fileUuid: string; // "90j3z7rmRphDPrdVgP9udFBaYar#oK0TWZIV"
|
||||||
formatType: string; // 1
|
formatType: number; // 1
|
||||||
invalidState: number; // 0
|
invalidState: number; // 0
|
||||||
md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6"
|
md5HexStr: string; // "e4d09c784d5a2abcb2f9980bdc7acfe6"
|
||||||
playState: number; // 0
|
playState: number; // 0
|
||||||
@@ -589,6 +449,7 @@ export interface PttElement {
|
|||||||
voiceChangeType: number; // 0
|
voiceChangeType: number; // 0
|
||||||
voiceType: number; // 0
|
voiceType: number; // 0
|
||||||
waveAmplitudes: number[];
|
waveAmplitudes: number[];
|
||||||
|
autoConvertText: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ArkElement {
|
export interface ArkElement {
|
||||||
@@ -794,7 +655,8 @@ export interface InlineKeyboardElementRowButton {
|
|||||||
export interface InlineKeyboardElement {
|
export interface InlineKeyboardElement {
|
||||||
rows: [{
|
rows: [{
|
||||||
buttons: InlineKeyboardElementRowButton[]
|
buttons: InlineKeyboardElementRowButton[]
|
||||||
}];
|
}],
|
||||||
|
botAppid: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TipAioOpGrayTipElement { // 这是什么提示来着?
|
export interface TipAioOpGrayTipElement { // 这是什么提示来着?
|
||||||
|
4
src/core/external/offset.json
vendored
4
src/core/external/offset.json
vendored
@@ -34,5 +34,9 @@
|
|||||||
"3.2.12-28971-arm64": {
|
"3.2.12-28971-arm64": {
|
||||||
"send": "6E91318",
|
"send": "6E91318",
|
||||||
"recv": "6E94B50"
|
"recv": "6E94B50"
|
||||||
|
},
|
||||||
|
"6.9.56-28418-arm64": {
|
||||||
|
"send": "4471360",
|
||||||
|
"recv": "4473BCC"
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -71,7 +71,8 @@ export class NodeIKernelGroupListener {
|
|||||||
sceneId: string,
|
sceneId: string,
|
||||||
ids: string[],
|
ids: string[],
|
||||||
infos: Map<string, GroupMember>, // uid -> GroupMember
|
infos: Map<string, GroupMember>, // uid -> GroupMember
|
||||||
finish: boolean,
|
hasPrev: boolean,
|
||||||
|
hasNext: boolean,
|
||||||
hasRobot: boolean
|
hasRobot: boolean
|
||||||
}) {
|
}) {
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,7 @@ export class PacketClient {
|
|||||||
this.websocket.onopen = () => {
|
this.websocket.onopen = () => {
|
||||||
this.isConnected = true;
|
this.isConnected = true;
|
||||||
this.reconnectAttempts = 0;
|
this.reconnectAttempts = 0;
|
||||||
this.logger.log.bind(this.logger)(`[Core] [Packet Server] Connected to ${this.clientUrl}`);
|
this.logger.log.bind(this.logger)(`[Core] [Packet Server] 已连接到 ${this.clientUrl}`);
|
||||||
cb();
|
cb();
|
||||||
resolve();
|
resolve();
|
||||||
};
|
};
|
||||||
@@ -85,14 +85,14 @@ export class PacketClient {
|
|||||||
this.reconnectAttempts++;
|
this.reconnectAttempts++;
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.connect(cb).catch((error) => {
|
this.connect(cb).catch((error) => {
|
||||||
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] Reconnecting attempt failed,${error.message}`);
|
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] 尝试重连失败:${error.message}`);
|
||||||
});
|
});
|
||||||
}, 5000 * this.reconnectAttempts);
|
}, 5000 * this.reconnectAttempts);
|
||||||
} else {
|
} else {
|
||||||
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] Max reconnect attempts reached. ${this.clientUrl}`);
|
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] ${this.clientUrl} 已达到最大重连次数!`);
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
this.logger.logError.bind(this.logger)(`Error attempting to reconnect: ${error.message}`);
|
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] 重连时出错: ${error.message}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,7 +165,7 @@ export class PacketClient {
|
|||||||
// 校验失败和异常 可能返回undefined
|
// 校验失败和异常 可能返回undefined
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
if (!this.available) {
|
if (!this.available) {
|
||||||
this.logger.logError('NapCat.Packet is not init');
|
this.logger.logError('NapCat.Packet 未初始化!');
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
const md5 = crypto.createHash('md5').update(data).digest('hex');
|
const md5 = crypto.createHash('md5').update(data).digest('hex');
|
||||||
|
@@ -167,7 +167,7 @@ export class PacketHighwaySession {
|
|||||||
});
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1004,
|
1004,
|
||||||
fs.createReadStream(img.path, {highWaterMark: BlockSize}),
|
fs.createReadStream(img.path, { highWaterMark: BlockSize }),
|
||||||
img.size,
|
img.size,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -207,7 +207,7 @@ export class PacketHighwaySession {
|
|||||||
});
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1003,
|
1003,
|
||||||
fs.createReadStream(img.path, {highWaterMark: BlockSize}),
|
fs.createReadStream(img.path, { highWaterMark: BlockSize }),
|
||||||
img.size,
|
img.size,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -244,10 +244,10 @@ export class PacketHighwaySession {
|
|||||||
hash: {
|
hash: {
|
||||||
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1005,
|
1005,
|
||||||
fs.createReadStream(video.filePath!, {highWaterMark: BlockSize}),
|
fs.createReadStream(video.filePath!, { highWaterMark: BlockSize }),
|
||||||
+video.fileSize!,
|
+video.fileSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -275,7 +275,7 @@ export class PacketHighwaySession {
|
|||||||
});
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1006,
|
1006,
|
||||||
fs.createReadStream(video.thumbPath!, {highWaterMark: BlockSize}),
|
fs.createReadStream(video.thumbPath!, { highWaterMark: BlockSize }),
|
||||||
+video.thumbSize!,
|
+video.thumbSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -312,10 +312,10 @@ export class PacketHighwaySession {
|
|||||||
hash: {
|
hash: {
|
||||||
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
fileSha1: await calculateSha1StreamBytes(video.filePath!)
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1001,
|
1001,
|
||||||
fs.createReadStream(video.filePath!, {highWaterMark: BlockSize}),
|
fs.createReadStream(video.filePath!, { highWaterMark: BlockSize }),
|
||||||
+video.fileSize!,
|
+video.fileSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -343,7 +343,7 @@ export class PacketHighwaySession {
|
|||||||
});
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1002,
|
1002,
|
||||||
fs.createReadStream(video.thumbPath!, {highWaterMark: BlockSize}),
|
fs.createReadStream(video.thumbPath!, { highWaterMark: BlockSize }),
|
||||||
+video.thumbSize!,
|
+video.thumbSize!,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -379,10 +379,10 @@ export class PacketHighwaySession {
|
|||||||
hash: {
|
hash: {
|
||||||
fileSha1: [sha1]
|
fileSha1: [sha1]
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1008,
|
1008,
|
||||||
fs.createReadStream(ptt.filePath, {highWaterMark: BlockSize}),
|
fs.createReadStream(ptt.filePath, { highWaterMark: BlockSize }),
|
||||||
ptt.fileSize,
|
ptt.fileSize,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -418,10 +418,10 @@ export class PacketHighwaySession {
|
|||||||
hash: {
|
hash: {
|
||||||
fileSha1: [sha1]
|
fileSha1: [sha1]
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
1007,
|
1007,
|
||||||
fs.createReadStream(ptt.filePath, {highWaterMark: BlockSize}),
|
fs.createReadStream(ptt.filePath, { highWaterMark: BlockSize }),
|
||||||
ptt.fileSize,
|
ptt.fileSize,
|
||||||
md5,
|
md5,
|
||||||
extend
|
extend
|
||||||
@@ -484,10 +484,10 @@ export class PacketHighwaySession {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
unknown200: 0,
|
unknown200: 0,
|
||||||
})
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
71,
|
71,
|
||||||
fs.createReadStream(file.filePath, {highWaterMark: BlockSize}),
|
fs.createReadStream(file.filePath, { highWaterMark: BlockSize }),
|
||||||
file.fileSize,
|
file.fileSize,
|
||||||
file.fileMd5,
|
file.fileMd5,
|
||||||
ext
|
ext
|
||||||
@@ -549,10 +549,10 @@ export class PacketHighwaySession {
|
|||||||
},
|
},
|
||||||
unknown200: 1,
|
unknown200: 1,
|
||||||
unknown3: 0
|
unknown3: 0
|
||||||
})
|
});
|
||||||
await this.packetHighwayClient.upload(
|
await this.packetHighwayClient.upload(
|
||||||
95,
|
95,
|
||||||
fs.createReadStream(file.filePath, {highWaterMark: BlockSize}),
|
fs.createReadStream(file.filePath, { highWaterMark: BlockSize }),
|
||||||
file.fileSize,
|
file.fileSize,
|
||||||
file.fileMd5,
|
file.fileMd5,
|
||||||
ext
|
ext
|
||||||
|
@@ -30,7 +30,7 @@ abstract class HighwayUploader {
|
|||||||
reject(new Error(`[Highway] timeout after ${this.trans.timeout}s`));
|
reject(new Error(`[Highway] timeout after ${this.trans.timeout}s`));
|
||||||
}, (this.trans.timeout ?? Infinity) * 1000
|
}, (this.trans.timeout ?? Infinity) * 1000
|
||||||
);
|
);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildPicUpHead(offset: number, bodyLength: number, bodyMd5: Uint8Array): Uint8Array {
|
buildPicUpHead(offset: number, bodyLength: number, bodyMd5: Uint8Array): Uint8Array {
|
||||||
@@ -100,7 +100,7 @@ export class HighwayTcpUploader extends HighwayUploader {
|
|||||||
const upload = new Promise<void>((resolve, reject) => {
|
const upload = new Promise<void>((resolve, reject) => {
|
||||||
const highwayTransForm = new HighwayTcpUploaderTransform(this);
|
const highwayTransForm = new HighwayTcpUploaderTransform(this);
|
||||||
const socket = net.connect(this.trans.port, this.trans.server, () => {
|
const socket = net.connect(this.trans.port, this.trans.server, () => {
|
||||||
this.trans.data.pipe(highwayTransForm).pipe(socket, {end: false});
|
this.trans.data.pipe(highwayTransForm).pipe(socket, { end: false });
|
||||||
});
|
});
|
||||||
const handleRspHeader = (header: Buffer) => {
|
const handleRspHeader = (header: Buffer) => {
|
||||||
const rsp = new NapProtoMsg(RespDataHighwayHead).decode(header);
|
const rsp = new NapProtoMsg(RespDataHighwayHead).decode(header);
|
||||||
@@ -159,7 +159,7 @@ export class HighwayHttpUploader extends HighwayUploader {
|
|||||||
try {
|
try {
|
||||||
await this.uploadBlock(block, offset);
|
await this.uploadBlock(block, offset);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new Error(`[Highway] httpUpload Error uploading block at offset ${offset}: ${err}`)
|
throw new Error(`[Highway] httpUpload Error uploading block at offset ${offset}: ${err}`);
|
||||||
}
|
}
|
||||||
offset += block.length;
|
offset += block.length;
|
||||||
}
|
}
|
||||||
|
@@ -15,9 +15,9 @@ export class PacketMsgBuilder {
|
|||||||
|
|
||||||
protected static failBackText = new PacketMsgTextElement(
|
protected static failBackText = new PacketMsgTextElement(
|
||||||
{
|
{
|
||||||
textElement: {content: "[该消息类型暂不支持查看]"}!
|
textElement: { content: "[该消息类型暂不支持查看]" }!
|
||||||
} as SendTextElement
|
} as SendTextElement
|
||||||
)
|
);
|
||||||
|
|
||||||
buildFakeMsg(selfUid: string, element: PacketMsg[]): NapProtoEncodeStructType<typeof PushMsgBody>[] {
|
buildFakeMsg(selfUid: string, element: PacketMsg[]): NapProtoEncodeStructType<typeof PushMsgBody>[] {
|
||||||
return element.map((node): NapProtoEncodeStructType<typeof PushMsgBody> => {
|
return element.map((node): NapProtoEncodeStructType<typeof PushMsgBody> => {
|
||||||
@@ -50,7 +50,7 @@ export class PacketMsgBuilder {
|
|||||||
divSeq: node.groupId ? undefined : 4,
|
divSeq: node.groupId ? undefined : 4,
|
||||||
msgId: crypto.randomBytes(4).readUInt32LE(0),
|
msgId: crypto.randomBytes(4).readUInt32LE(0),
|
||||||
sequence: crypto.randomBytes(4).readUInt32LE(0),
|
sequence: crypto.randomBytes(4).readUInt32LE(0),
|
||||||
timeStamp: Math.floor(Date.now() / 1000),
|
timeStamp: +node.time.toString().substring(0, 10),
|
||||||
field7: BigInt(1),
|
field7: BigInt(1),
|
||||||
field8: 0,
|
field8: 0,
|
||||||
field9: 0,
|
field9: 0,
|
||||||
|
@@ -1,4 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
|
Peer,
|
||||||
|
ChatType,
|
||||||
|
ElementType,
|
||||||
MessageElement,
|
MessageElement,
|
||||||
RawMessage,
|
RawMessage,
|
||||||
SendArkElement,
|
SendArkElement,
|
||||||
@@ -31,27 +34,39 @@ import {
|
|||||||
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message";
|
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message";
|
||||||
import { LogWrapper } from "@/common/log";
|
import { LogWrapper } from "@/common/log";
|
||||||
|
|
||||||
type SendMessageElementMap = {
|
const SupportedElementTypes = [
|
||||||
textElement: SendTextElement,
|
ElementType.TEXT,
|
||||||
picElement: SendPicElement,
|
ElementType.PIC,
|
||||||
replyElement: SendReplyElement,
|
ElementType.REPLY,
|
||||||
faceElement: SendFaceElement,
|
ElementType.FACE,
|
||||||
marketFaceElement: SendMarketFaceElement,
|
ElementType.MFACE,
|
||||||
videoElement: SendVideoElement,
|
ElementType.VIDEO,
|
||||||
fileElement: SendFileElement,
|
ElementType.FILE,
|
||||||
pttElement: SendPttElement,
|
ElementType.PTT,
|
||||||
arkElement: SendArkElement,
|
ElementType.ARK,
|
||||||
markdownElement: SendMarkdownElement,
|
ElementType.MARKDOWN,
|
||||||
structLongMsgElement: SendStructLongMsgElement
|
ElementType.STRUCTLONGMSG
|
||||||
|
];
|
||||||
|
|
||||||
|
type SendMessageTypeElementMap = {
|
||||||
|
[ElementType.TEXT]: SendTextElement,
|
||||||
|
[ElementType.PIC]: SendPicElement,
|
||||||
|
[ElementType.FILE]: SendFileElement,
|
||||||
|
[ElementType.PTT]: SendPttElement,
|
||||||
|
[ElementType.VIDEO]: SendVideoElement,
|
||||||
|
[ElementType.FACE]: SendFaceElement,
|
||||||
|
[ElementType.REPLY]: SendReplyElement,
|
||||||
|
[ElementType.ARK]: SendArkElement,
|
||||||
|
[ElementType.MFACE]: SendMarketFaceElement,
|
||||||
|
[ElementType.STRUCTLONGMSG]: SendStructLongMsgElement,
|
||||||
|
[ElementType.MARKDOWN]: SendMarkdownElement,
|
||||||
};
|
};
|
||||||
|
|
||||||
type RawToPacketMsgConverters = {
|
type ElementToPacketMsgConverters = {
|
||||||
[K in keyof SendMessageElementMap]: (
|
[K in keyof SendMessageTypeElementMap]: (
|
||||||
element: SendMessageElementMap[K],
|
sendElement: MessageElement
|
||||||
msg?: RawMessage,
|
) => IPacketMsgElement<SendMessageTypeElementMap[K]>;
|
||||||
elementWrapper?: MessageElement,
|
}
|
||||||
) => IPacketMsgElement<SendMessageElementMap[K]> | null;
|
|
||||||
};
|
|
||||||
|
|
||||||
export type rawMsgWithSendMsg = {
|
export type rawMsgWithSendMsg = {
|
||||||
senderUin: number;
|
senderUin: number;
|
||||||
@@ -69,6 +84,10 @@ export class PacketMsgConverter {
|
|||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isValidElementType(type: ElementType): type is keyof ElementToPacketMsgConverters {
|
||||||
|
return SupportedElementTypes.includes(type);
|
||||||
|
}
|
||||||
|
|
||||||
rawMsgWithSendMsgToPacketMsg(msg: rawMsgWithSendMsg): PacketMsg {
|
rawMsgWithSendMsgToPacketMsg(msg: rawMsgWithSendMsg): PacketMsg {
|
||||||
return {
|
return {
|
||||||
senderUid: msg.senderUid ?? '',
|
senderUid: msg.senderUid ?? '',
|
||||||
@@ -77,55 +96,68 @@ export class PacketMsgConverter {
|
|||||||
groupId: msg.groupId,
|
groupId: msg.groupId,
|
||||||
time: msg.time,
|
time: msg.time,
|
||||||
msg: msg.msg.map((element) => {
|
msg: msg.msg.map((element) => {
|
||||||
const key = (Object.keys(this.rawToPacketMsgConverters) as Array<keyof SendMessageElementMap>).find(
|
if (!this.isValidElementType(element.elementType)) return null;
|
||||||
(k) => (element as any)[k] !== undefined // TODO:
|
return this.rawToPacketMsgConverters[element.elementType](element as MessageElement);
|
||||||
);
|
|
||||||
if (key) {
|
|
||||||
const elementData = (element as any)[key]; // TODO:
|
|
||||||
if (elementData) return this.rawToPacketMsgConverters[key](element as any);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}).filter((e) => e !== null)
|
}).filter((e) => e !== null)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private rawToPacketMsgConverters: RawToPacketMsgConverters = {
|
rawMsgToPacketMsg(msg: RawMessage, ctxPeer: Peer): PacketMsg {
|
||||||
textElement: (element: SendTextElement) => {
|
return {
|
||||||
if (element.textElement.atType) {
|
seq: +msg.msgSeq,
|
||||||
return new PacketMsgAtElement(element);
|
groupId: ctxPeer.chatType === ChatType.KCHATTYPEGROUP ? +msg.peerUid : undefined,
|
||||||
|
senderUid: msg.senderUid,
|
||||||
|
senderUin: +msg.senderUin,
|
||||||
|
senderName: msg.sendMemberName && msg.sendMemberName !== ''
|
||||||
|
? msg.sendMemberName
|
||||||
|
: msg.sendNickName && msg.sendNickName !== ''
|
||||||
|
? msg.sendNickName
|
||||||
|
: "QQ用户",
|
||||||
|
time: +msg.msgTime,
|
||||||
|
msg: msg.elements.map((element) => {
|
||||||
|
if (!this.isValidElementType(element.elementType)) return null;
|
||||||
|
return this.rawToPacketMsgConverters[element.elementType](element);
|
||||||
|
}).filter((e) => e !== null)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private rawToPacketMsgConverters: ElementToPacketMsgConverters = {
|
||||||
|
[ElementType.TEXT]: (element) => {
|
||||||
|
if (element.textElement?.atType) {
|
||||||
|
return new PacketMsgAtElement(element as SendTextElement);
|
||||||
}
|
}
|
||||||
return new PacketMsgTextElement(element);
|
return new PacketMsgTextElement(element as SendTextElement);
|
||||||
},
|
},
|
||||||
picElement: (element: SendPicElement) => {
|
[ElementType.PIC]: (element) => {
|
||||||
return new PacketMsgPicElement(element);
|
return new PacketMsgPicElement(element as SendPicElement);
|
||||||
},
|
},
|
||||||
replyElement: (element: SendReplyElement) => {
|
[ElementType.REPLY]: (element) => {
|
||||||
return new PacketMsgReplyElement(element);
|
return new PacketMsgReplyElement(element as SendReplyElement);
|
||||||
},
|
},
|
||||||
faceElement: (element: SendFaceElement) => {
|
[ElementType.FACE]: (element) => {
|
||||||
return new PacketMsgFaceElement(element);
|
return new PacketMsgFaceElement(element as SendFaceElement);
|
||||||
},
|
},
|
||||||
marketFaceElement: (element: SendMarketFaceElement) => {
|
[ElementType.MFACE]: (element) => {
|
||||||
return new PacketMsgMarkFaceElement(element);
|
return new PacketMsgMarkFaceElement(element as SendMarketFaceElement);
|
||||||
},
|
},
|
||||||
videoElement: (element: SendVideoElement) => {
|
[ElementType.VIDEO]: (element) => {
|
||||||
return new PacketMsgVideoElement(element);
|
return new PacketMsgVideoElement(element as SendVideoElement);
|
||||||
},
|
},
|
||||||
fileElement: (element: SendFileElement) => {
|
[ElementType.FILE]: (element) => {
|
||||||
return new PacketMsgFileElement(element);
|
return new PacketMsgFileElement(element as SendFileElement);
|
||||||
},
|
},
|
||||||
pttElement: (element: SendPttElement) => {
|
[ElementType.PTT]: (element) => {
|
||||||
return new PacketMsgPttElement(element);
|
return new PacketMsgPttElement(element as SendPttElement);
|
||||||
},
|
},
|
||||||
arkElement: (element: SendArkElement) => {
|
[ElementType.ARK]: (element) => {
|
||||||
return new PacketMsgLightAppElement(element);
|
return new PacketMsgLightAppElement(element as SendArkElement);
|
||||||
},
|
},
|
||||||
markdownElement: (element: SendMarkdownElement) => {
|
[ElementType.MARKDOWN]: (element) => {
|
||||||
return new PacketMsgMarkDownElement(element);
|
return new PacketMsgMarkDownElement(element as SendMarkdownElement);
|
||||||
},
|
},
|
||||||
// TODO: check this logic, move it in arkElement?
|
// TODO: check this logic, move it in arkElement?
|
||||||
structLongMsgElement: (element: SendStructLongMsgElement) => {
|
[ElementType.STRUCTLONGMSG]: (element) => {
|
||||||
return new PacketMultiMsgElement(element);
|
return new PacketMultiMsgElement(element as SendStructLongMsgElement);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -89,11 +89,11 @@ export class PacketMsgAtElement extends PacketMsgTextElement {
|
|||||||
text: {
|
text: {
|
||||||
str: this.text,
|
str: this.text,
|
||||||
pbReserve: new NapProtoMsg(MentionExtra).encode({
|
pbReserve: new NapProtoMsg(MentionExtra).encode({
|
||||||
type: this.atAll ? 1 : 2,
|
type: this.atAll ? 1 : 2,
|
||||||
uin: 0,
|
uin: 0,
|
||||||
field5: 0,
|
field5: 0,
|
||||||
uid: this.targetUid,
|
uid: this.targetUid,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
@@ -308,7 +308,7 @@ export class PacketMsgVideoElement extends IPacketMsgElement<SendVideoElement> {
|
|||||||
this.filePath = element.videoElement.filePath;
|
this.filePath = element.videoElement.filePath;
|
||||||
this.thumbSize = element.videoElement.thumbSize;
|
this.thumbSize = element.videoElement.thumbSize;
|
||||||
this.thumbPath = element.videoElement.thumbPath?.get(0);
|
this.thumbPath = element.videoElement.thumbPath?.get(0);
|
||||||
this.fileMd5 = element.videoElement.videoMd5
|
this.fileMd5 = element.videoElement.videoMd5;
|
||||||
this.thumbMd5 = element.videoElement.thumbMd5;
|
this.thumbMd5 = element.videoElement.thumbMd5;
|
||||||
this.thumbWidth = element.videoElement.thumbWidth;
|
this.thumbWidth = element.videoElement.thumbWidth;
|
||||||
this.thumbHeight = element.videoElement.thumbHeight;
|
this.thumbHeight = element.videoElement.thumbHeight;
|
||||||
@@ -355,7 +355,7 @@ export class PacketMsgPttElement extends IPacketMsgElement<SendPttElement> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
||||||
return []
|
return [];
|
||||||
// if (!this.msgInfo) return [];
|
// if (!this.msgInfo) return [];
|
||||||
// return [{
|
// return [{
|
||||||
// commonElem: {
|
// commonElem: {
|
||||||
@@ -382,7 +382,7 @@ export class PacketMsgFileElement extends IPacketMsgElement<SendFileElement> {
|
|||||||
isGroupFile?: boolean;
|
isGroupFile?: boolean;
|
||||||
_private_send_uid?: string;
|
_private_send_uid?: string;
|
||||||
_private_recv_uid?: string;
|
_private_recv_uid?: string;
|
||||||
_e37_800_rsp?: NapProtoEncodeStructType<typeof OidbSvcTrpcTcp0XE37_800Response>
|
_e37_800_rsp?: NapProtoEncodeStructType<typeof OidbSvcTrpcTcp0XE37_800Response>;
|
||||||
|
|
||||||
constructor(element: SendFileElement) {
|
constructor(element: SendFileElement) {
|
||||||
super(element);
|
super(element);
|
||||||
@@ -423,7 +423,7 @@ export class PacketMsgFileElement extends IPacketMsgElement<SendFileElement> {
|
|||||||
destUid: this._private_recv_uid,
|
destUid: this._private_recv_uid,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
buildElement(): NapProtoEncodeStructType<typeof Elem>[] {
|
||||||
@@ -443,7 +443,7 @@ export class PacketMsgFileElement extends IPacketMsgElement<SendFileElement> {
|
|||||||
fileMd5: this.fileMd5,
|
fileMd5: this.fileMd5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
lb.writeUInt16BE(transElemVal.length);
|
lb.writeUInt16BE(transElemVal.length);
|
||||||
return [{
|
return [{
|
||||||
transElem: {
|
transElem: {
|
||||||
|
@@ -61,7 +61,7 @@ export class PacketPacker {
|
|||||||
return {
|
return {
|
||||||
cmd: `OidbSvcTrpcTcp.0x${cmd.toString(16).toUpperCase()}_${subCmd}`,
|
cmd: `OidbSvcTrpcTcp.0x${cmd.toString(16).toUpperCase()}_${subCmd}`,
|
||||||
data: this.packetPacket(data)
|
data: this.packetPacket(data)
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
packPokePacket(peer: number, group?: number): OidbPacket {
|
packPokePacket(peer: number, group?: number): OidbPacket {
|
||||||
@@ -114,7 +114,7 @@ export class PacketPacker {
|
|||||||
packStatusPacket(uin: number): OidbPacket {
|
packStatusPacket(uin: number): OidbPacket {
|
||||||
const oidb_0xfe1_2 = new NapProtoMsg(OidbSvcTrpcTcp0XFE1_2).encode({
|
const oidb_0xfe1_2 = new NapProtoMsg(OidbSvcTrpcTcp0XFE1_2).encode({
|
||||||
uin: uin,
|
uin: uin,
|
||||||
key: [{key: 27372}]
|
key: [{ key: 27372 }]
|
||||||
});
|
});
|
||||||
return this.packOidbPacket(0xfe1, 2, oidb_0xfe1_2);
|
return this.packOidbPacket(0xfe1, 2, oidb_0xfe1_2);
|
||||||
}
|
}
|
||||||
@@ -240,68 +240,68 @@ export class PacketPacker {
|
|||||||
|
|
||||||
async packUploadC2CImgReq(peerUin: string, img: PacketMsgPicElement): Promise<OidbPacket> {
|
async packUploadC2CImgReq(peerUin: string, img: PacketMsgPicElement): Promise<OidbPacket> {
|
||||||
const req = new NapProtoMsg(NTV2RichMediaReq).encode({
|
const req = new NapProtoMsg(NTV2RichMediaReq).encode({
|
||||||
reqHead: {
|
reqHead: {
|
||||||
common: {
|
common: {
|
||||||
requestId: 1,
|
requestId: 1,
|
||||||
command: 100
|
command: 100
|
||||||
|
},
|
||||||
|
scene: {
|
||||||
|
requestType: 2,
|
||||||
|
businessType: 1,
|
||||||
|
sceneType: 1,
|
||||||
|
c2C: {
|
||||||
|
accountType: 2,
|
||||||
|
targetUid: peerUin
|
||||||
},
|
},
|
||||||
scene: {
|
},
|
||||||
requestType: 2,
|
client: {
|
||||||
businessType: 1,
|
agentType: 2,
|
||||||
sceneType: 1,
|
}
|
||||||
c2C: {
|
},
|
||||||
accountType: 2,
|
upload: {
|
||||||
targetUid: peerUin
|
uploadInfo: [
|
||||||
|
{
|
||||||
|
fileInfo: {
|
||||||
|
fileSize: +img.size,
|
||||||
|
fileHash: img.md5,
|
||||||
|
fileSha1: img.sha1!,
|
||||||
|
fileName: img.name,
|
||||||
|
type: {
|
||||||
|
type: 1,
|
||||||
|
picFormat: img.picType, //TODO: extend NapCat imgType /cc @MliKiowa
|
||||||
|
videoFormat: 0,
|
||||||
|
voiceFormat: 0,
|
||||||
|
},
|
||||||
|
width: img.width,
|
||||||
|
height: img.height,
|
||||||
|
time: 0,
|
||||||
|
original: 1
|
||||||
},
|
},
|
||||||
|
subFileType: 0,
|
||||||
|
}
|
||||||
|
],
|
||||||
|
tryFastUploadCompleted: true,
|
||||||
|
srvSendMsg: false,
|
||||||
|
clientRandomId: crypto.randomBytes(8).readBigUInt64BE() & BigInt('0x7FFFFFFFFFFFFFFF'),
|
||||||
|
compatQMsgSceneType: 1,
|
||||||
|
extBizInfo: {
|
||||||
|
pic: {
|
||||||
|
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
||||||
|
textSummary: "Nya~", // TODO:
|
||||||
},
|
},
|
||||||
client: {
|
video: {
|
||||||
agentType: 2,
|
bytesPbReserve: Buffer.alloc(0),
|
||||||
|
},
|
||||||
|
ptt: {
|
||||||
|
bytesPbReserve: Buffer.alloc(0),
|
||||||
|
bytesReserve: Buffer.alloc(0),
|
||||||
|
bytesGeneralFlags: Buffer.alloc(0),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
upload: {
|
clientSeq: 0,
|
||||||
uploadInfo: [
|
noNeedCompatMsg: false,
|
||||||
{
|
|
||||||
fileInfo: {
|
|
||||||
fileSize: +img.size,
|
|
||||||
fileHash: img.md5,
|
|
||||||
fileSha1: img.sha1!,
|
|
||||||
fileName: img.name,
|
|
||||||
type: {
|
|
||||||
type: 1,
|
|
||||||
picFormat: img.picType, //TODO: extend NapCat imgType /cc @MliKiowa
|
|
||||||
videoFormat: 0,
|
|
||||||
voiceFormat: 0,
|
|
||||||
},
|
|
||||||
width: img.width,
|
|
||||||
height: img.height,
|
|
||||||
time: 0,
|
|
||||||
original: 1
|
|
||||||
},
|
|
||||||
subFileType: 0,
|
|
||||||
}
|
|
||||||
],
|
|
||||||
tryFastUploadCompleted: true,
|
|
||||||
srvSendMsg: false,
|
|
||||||
clientRandomId: crypto.randomBytes(8).readBigUInt64BE() & BigInt('0x7FFFFFFFFFFFFFFF'),
|
|
||||||
compatQMsgSceneType: 1,
|
|
||||||
extBizInfo: {
|
|
||||||
pic: {
|
|
||||||
bytesPbReserveTroop: Buffer.from("0800180020004200500062009201009a0100a2010c080012001800200028003a00", 'hex'),
|
|
||||||
textSummary: "Nya~", // TODO:
|
|
||||||
},
|
|
||||||
video: {
|
|
||||||
bytesPbReserve: Buffer.alloc(0),
|
|
||||||
},
|
|
||||||
ptt: {
|
|
||||||
bytesPbReserve: Buffer.alloc(0),
|
|
||||||
bytesReserve: Buffer.alloc(0),
|
|
||||||
bytesGeneralFlags: Buffer.alloc(0),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clientSeq: 0,
|
|
||||||
noNeedCompatMsg: false,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
return this.packOidbPacket(0x11c5, 100, req, true, false);
|
return this.packOidbPacket(0x11c5, 100, req, true, false);
|
||||||
}
|
}
|
||||||
@@ -538,7 +538,7 @@ export class PacketPacker {
|
|||||||
clientSeq: 0,
|
clientSeq: 0,
|
||||||
noNeedCompatMsg: false
|
noNeedCompatMsg: false
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return this.packOidbPacket(0x126E, 100, req, true, false);
|
return this.packOidbPacket(0x126E, 100, req, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,7 +600,7 @@ export class PacketPacker {
|
|||||||
clientSeq: 0,
|
clientSeq: 0,
|
||||||
noNeedCompatMsg: false
|
noNeedCompatMsg: false
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
return this.packOidbPacket(0x126D, 100, req, true, false);
|
return this.packOidbPacket(0x126D, 100, req, true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,7 +642,7 @@ export class PacketPacker {
|
|||||||
businessId: 3,
|
businessId: 3,
|
||||||
clientType: 1,
|
clientType: 1,
|
||||||
flagSupportMediaPlatform: 1
|
flagSupportMediaPlatform: 1
|
||||||
})
|
});
|
||||||
return this.packOidbPacket(0xE37, 1700, body, false, false);
|
return this.packOidbPacket(0xE37, 1700, body, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,13 +664,13 @@ export class PacketPacker {
|
|||||||
|
|
||||||
packGroupFileDownloadReq(groupUin: number, fileUUID: string): OidbPacket {
|
packGroupFileDownloadReq(groupUin: number, fileUUID: string): OidbPacket {
|
||||||
return this.packOidbPacket(0x6D6, 2, new NapProtoMsg(OidbSvcTrpcTcp0x6D6).encode({
|
return this.packOidbPacket(0x6D6, 2, new NapProtoMsg(OidbSvcTrpcTcp0x6D6).encode({
|
||||||
download: {
|
download: {
|
||||||
groupUin: groupUin,
|
groupUin: groupUin,
|
||||||
appId: 7,
|
appId: 7,
|
||||||
busId: 102,
|
busId: 102,
|
||||||
fileId: fileUUID
|
fileId: fileUUID
|
||||||
}
|
}
|
||||||
}), true, false
|
}), true, false
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -118,7 +118,7 @@ export const FileExtra = {
|
|||||||
|
|
||||||
export const PrivateFileExtra = {
|
export const PrivateFileExtra = {
|
||||||
field2: ProtoField(2, () => PrivateFileExtraField2),
|
field2: ProtoField(2, () => PrivateFileExtraField2),
|
||||||
}
|
};
|
||||||
|
|
||||||
export const PrivateFileExtraField2 = {
|
export const PrivateFileExtraField2 = {
|
||||||
field1: ProtoField(1, ScalarType.UINT32),
|
field1: ProtoField(1, ScalarType.UINT32),
|
||||||
@@ -131,7 +131,7 @@ export const PrivateFileExtraField2 = {
|
|||||||
fileHash: ProtoField(14, ScalarType.STRING),
|
fileHash: ProtoField(14, ScalarType.STRING),
|
||||||
selfUid: ProtoField(15, ScalarType.STRING),
|
selfUid: ProtoField(15, ScalarType.STRING),
|
||||||
destUid: ProtoField(16, ScalarType.STRING),
|
destUid: ProtoField(16, ScalarType.STRING),
|
||||||
}
|
};
|
||||||
|
|
||||||
export const GroupFileExtra = {
|
export const GroupFileExtra = {
|
||||||
field1: ProtoField(1, ScalarType.UINT32),
|
field1: ProtoField(1, ScalarType.UINT32),
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
import { ScalarType } from "@protobuf-ts/runtime";
|
import { ScalarType } from "@protobuf-ts/runtime";
|
||||||
import { ProtoField } from "../NapProto";
|
import { ProtoField } from "../NapProto";
|
||||||
import {OidbSvcTrpcTcp0XE37_800_1200Metadata} from "@/core/packet/proto/oidb/Oidb.0xE37_1200";
|
import { OidbSvcTrpcTcp0XE37_800_1200Metadata } from "@/core/packet/proto/oidb/Oidb.0xE37_1200";
|
||||||
|
|
||||||
export const OidbSvcTrpcTcp0XE37_800 = {
|
export const OidbSvcTrpcTcp0XE37_800 = {
|
||||||
subCommand: ProtoField(1, ScalarType.UINT32),
|
subCommand: ProtoField(1, ScalarType.UINT32),
|
||||||
@@ -59,4 +59,4 @@ export const OidbSvcTrpcTcp0XE37_800Response = {
|
|||||||
export const OidbSvcTrpcTcp0XE37_800ResponseBody = {
|
export const OidbSvcTrpcTcp0XE37_800ResponseBody = {
|
||||||
field10: ProtoField(10, ScalarType.UINT32, true),
|
field10: ProtoField(10, ScalarType.UINT32, true),
|
||||||
field30: ProtoField(30, () => OidbSvcTrpcTcp0XE37_800_1200Metadata, true),
|
field30: ProtoField(30, () => OidbSvcTrpcTcp0XE37_800_1200Metadata, true),
|
||||||
}
|
};
|
||||||
|
@@ -8,7 +8,7 @@ export const OidbSvcTrpcTcp0XE37_1700 = {
|
|||||||
businessId: ProtoField(101, ScalarType.INT32, true),
|
businessId: ProtoField(101, ScalarType.INT32, true),
|
||||||
clientType: ProtoField(102, ScalarType.INT32, true),
|
clientType: ProtoField(102, ScalarType.INT32, true),
|
||||||
flagSupportMediaPlatform: ProtoField(200, ScalarType.INT32, true),
|
flagSupportMediaPlatform: ProtoField(200, ScalarType.INT32, true),
|
||||||
}
|
};
|
||||||
|
|
||||||
export const ApplyUploadReqV3 = {
|
export const ApplyUploadReqV3 = {
|
||||||
senderUid: ProtoField(10, ScalarType.STRING, true),
|
senderUid: ProtoField(10, ScalarType.STRING, true),
|
||||||
@@ -20,4 +20,4 @@ export const ApplyUploadReqV3 = {
|
|||||||
localPath: ProtoField(70, ScalarType.STRING, true),
|
localPath: ProtoField(70, ScalarType.STRING, true),
|
||||||
md5CheckSum: ProtoField(110, ScalarType.BYTES, true),
|
md5CheckSum: ProtoField(110, ScalarType.BYTES, true),
|
||||||
sha3CheckSum: ProtoField(120, ScalarType.BYTES, true),
|
sha3CheckSum: ProtoField(120, ScalarType.BYTES, true),
|
||||||
}
|
};
|
||||||
|
@@ -9,4 +9,4 @@ export const OidbSvcTrpcTcp0XEB7_Body = {
|
|||||||
|
|
||||||
export const OidbSvcTrpcTcp0XEB7 = {
|
export const OidbSvcTrpcTcp0XEB7 = {
|
||||||
body: ProtoField(2, () => OidbSvcTrpcTcp0XEB7_Body),
|
body: ProtoField(2, () => OidbSvcTrpcTcp0XEB7_Body),
|
||||||
}
|
};
|
@@ -2,7 +2,7 @@
|
|||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
import * as stream from 'stream';
|
import * as stream from 'stream';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import {CalculateStreamBytesTransform} from "@/core/packet/utils/crypto/sha1StreamBytesTransform";
|
import { CalculateStreamBytesTransform } from "@/core/packet/utils/crypto/sha1StreamBytesTransform";
|
||||||
|
|
||||||
function sha1Stream(readable: stream.Readable) {
|
function sha1Stream(readable: stream.Readable) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@@ -73,7 +73,7 @@ export class Sha1Stream {
|
|||||||
|
|
||||||
this._count[1] = (this._count[1] + (dataLen >>> 29)) >>> 0;
|
this._count[1] = (this._count[1] + (dataLen >>> 29)) >>> 0;
|
||||||
|
|
||||||
let partLen = (this.Sha1BlockSize - index) >>> 0;
|
const partLen = (this.Sha1BlockSize - index) >>> 0;
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
|
||||||
if (dataLen >= partLen) {
|
if (dataLen >= partLen) {
|
||||||
@@ -100,11 +100,11 @@ export class Sha1Stream {
|
|||||||
|
|
||||||
public final(): Buffer {
|
public final(): Buffer {
|
||||||
const digest = Buffer.allocUnsafe(this.Sha1DigestSize);
|
const digest = Buffer.allocUnsafe(this.Sha1DigestSize);
|
||||||
const bits = Buffer.allocUnsafe(8)
|
const bits = Buffer.allocUnsafe(8);
|
||||||
bits.writeUInt32BE(this._count[1], 0);
|
bits.writeUInt32BE(this._count[1], 0);
|
||||||
bits.writeUInt32BE(this._count[0], 4);
|
bits.writeUInt32BE(this._count[0], 4);
|
||||||
|
|
||||||
let index = ((this._count[0] >>> 3) & 0x3F) >>> 0;
|
const index = ((this._count[0] >>> 3) & 0x3F) >>> 0;
|
||||||
const padLen = ((index < 56) ? (56 - index) : (120 - index)) >>> 0;
|
const padLen = ((index < 56) ? (56 - index) : (120 - index)) >>> 0;
|
||||||
this.update(this._padding, padLen);
|
this.update(this._padding, padLen);
|
||||||
this.update(bits);
|
this.update(bits);
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import * as stream from "node:stream";
|
import * as stream from "node:stream";
|
||||||
import {Sha1Stream} from "@/core/packet/utils/crypto/sha1Stream";
|
import { Sha1Stream } from "@/core/packet/utils/crypto/sha1Stream";
|
||||||
|
|
||||||
export class CalculateStreamBytesTransform extends stream.Transform {
|
export class CalculateStreamBytesTransform extends stream.Transform {
|
||||||
private readonly blockSize = 1024 * 1024;
|
private readonly blockSize = 1024 * 1024;
|
||||||
|
@@ -66,7 +66,11 @@ export interface NodeIKernelBuddyService {
|
|||||||
accept: boolean;
|
accept: boolean;
|
||||||
}): Promise<void>;
|
}): Promise<void>;
|
||||||
|
|
||||||
delBuddy(uid: number): void;
|
delBuddy(param: {
|
||||||
|
friendUid: string;
|
||||||
|
tempBlock: boolean;
|
||||||
|
tempBothDel: boolean;
|
||||||
|
}): Promise<unknown>;
|
||||||
|
|
||||||
delBatchBuddy(uids: number[]): void;
|
delBatchBuddy(uids: number[]): void;
|
||||||
|
|
||||||
|
@@ -12,6 +12,13 @@ import {
|
|||||||
import { GeneralCallResult } from '@/core/services/common';
|
import { GeneralCallResult } from '@/core/services/common';
|
||||||
|
|
||||||
export interface NodeIKernelGroupService {
|
export interface NodeIKernelGroupService {
|
||||||
|
// --->
|
||||||
|
// 待启用 For Next Version 3.2.0
|
||||||
|
// isTroopMember ? 0 : 111
|
||||||
|
getGroupMemberMaxNum(groupCode: string, serviceType: number): Promise<unknown>;
|
||||||
|
|
||||||
|
getAllGroupPrivilegeFlag(troopUinList: string[], serviceType: number): Promise<unknown>;
|
||||||
|
// <---
|
||||||
getGroupExt0xEF0Info(enableGroupCodes: string[], bannedGroupCodes: string[], filter: GroupExt0xEF0InfoFilter, forceFetch: boolean):
|
getGroupExt0xEF0Info(enableGroupCodes: string[], bannedGroupCodes: string[], filter: GroupExt0xEF0InfoFilter, forceFetch: boolean):
|
||||||
Promise<GeneralCallResult & { result: { groupExtInfos: Map<string, any> } }>;
|
Promise<GeneralCallResult & { result: { groupExtInfos: Map<string, any> } }>;
|
||||||
|
|
||||||
@@ -114,7 +121,7 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
destroyMemberListScene(SceneId: string): void;
|
destroyMemberListScene(SceneId: string): void;
|
||||||
|
|
||||||
getNextMemberList(sceneId: string, a: undefined, num: number): Promise<{
|
getNextMemberList(sceneId: string, groupMemberInfoListId: { index: number, uid: string } | undefined, num: number): Promise<{
|
||||||
errCode: number,
|
errCode: number,
|
||||||
errMsg: string,
|
errMsg: string,
|
||||||
result: { ids: string[], infos: Map<string, GroupMember>, finish: boolean, hasRobot: boolean }
|
result: { ids: string[], infos: Map<string, GroupMember>, finish: boolean, hasRobot: boolean }
|
||||||
@@ -225,7 +232,16 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
getGroupStatisticInfo(groupCode: string): unknown;
|
getGroupStatisticInfo(groupCode: string): unknown;
|
||||||
|
|
||||||
getGroupRemainAtTimes(groupCode: string): number;
|
getGroupRemainAtTimes(groupCode: string): Promise<Omit<GeneralCallResult, 'result'> & {
|
||||||
|
errCode: number,
|
||||||
|
atInfo: {
|
||||||
|
canAtAll: boolean
|
||||||
|
RemainAtAllCountForUin: number
|
||||||
|
RemainAtAllCountForGroup: number
|
||||||
|
atTimesMsg: string
|
||||||
|
canNotAtAllMsg: ''
|
||||||
|
}
|
||||||
|
}>;
|
||||||
|
|
||||||
getJoinGroupNoVerifyFlag(groupCode: string): unknown;
|
getJoinGroupNoVerifyFlag(groupCode: string): unknown;
|
||||||
|
|
||||||
|
@@ -327,8 +327,7 @@ export interface NodeIKernelMsgService {
|
|||||||
|
|
||||||
setPttPlayedState(...args: unknown[]): unknown;
|
setPttPlayedState(...args: unknown[]): unknown;
|
||||||
|
|
||||||
//uk1 uk2 true
|
fetchFavEmojiList(str: string, num: number, backward: boolean, forceRefresh: boolean): Promise<GeneralCallResult & {
|
||||||
fetchFavEmojiList(str: string, num: number, uk1: boolean, uk2: boolean): Promise<GeneralCallResult & {
|
|
||||||
emojiInfoList: Array<{
|
emojiInfoList: Array<{
|
||||||
uin: string,
|
uin: string,
|
||||||
emoId: number,
|
emoId: number,
|
||||||
|
@@ -86,7 +86,7 @@ export interface NodeQQNTWrapperUtil {
|
|||||||
|
|
||||||
calcThumbSize(arg0: number, arg1: number, arg2: unknown): unknown;
|
calcThumbSize(arg0: number, arg1: number, arg2: unknown): unknown;
|
||||||
|
|
||||||
fullWordToHalfWord(arg0: string): unknown;
|
fullWordToHalfWord(word: string): unknown;
|
||||||
|
|
||||||
getNTUserDataInfoConfig(): unknown;
|
getNTUserDataInfoConfig(): unknown;
|
||||||
|
|
||||||
|
27
src/onebot/action/go-cqhttp/GetGroupAtAllRemain.ts
Normal file
27
src/onebot/action/go-cqhttp/GetGroupAtAllRemain.ts
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
group_id: { type: ['number', 'string'] }
|
||||||
|
},
|
||||||
|
required: ['group_id'],
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class GoCQHTTPGetGroupAtAllRemain extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_GetGroupAtAllRemain;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
async _handle(payload: Payload) {
|
||||||
|
const ret = await this.core.apis.GroupApi.getGroupRemainAtTimes(payload.group_id.toString());
|
||||||
|
const data = {
|
||||||
|
can_at_all: ret.atInfo.canAtAll,
|
||||||
|
remain_at_all_count_for_group: ret.atInfo.RemainAtAllCountForGroup,
|
||||||
|
remain_at_all_count_for_uin: ret.atInfo.RemainAtAllCountForUin
|
||||||
|
};
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
21
src/onebot/action/go-cqhttp/GoCQHTTPCheckUrlSafely.ts
Normal file
21
src/onebot/action/go-cqhttp/GoCQHTTPCheckUrlSafely.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
url: { type: 'string' },
|
||||||
|
},
|
||||||
|
required: ['url'],
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class GoCQHTTPCheckUrlSafely extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_CheckUrlSafely;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
async _handle(payload: Payload) {
|
||||||
|
return { level: 1 };
|
||||||
|
}
|
||||||
|
}
|
38
src/onebot/action/go-cqhttp/GoCQHTTPDeleteFriend.ts
Normal file
38
src/onebot/action/go-cqhttp/GoCQHTTPDeleteFriend.ts
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
friend_id: { type: ['string', 'number'] },
|
||||||
|
temp_block: { type: 'boolean' },
|
||||||
|
temp_both_del: { type: 'boolean' },
|
||||||
|
},
|
||||||
|
required: ['friend_id'],
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class GoCQHTTPDeleteFriend extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_DeleteFriend;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
async _handle(payload: Payload) {
|
||||||
|
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.friend_id.toString());
|
||||||
|
|
||||||
|
if (!uid) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: '好友不存在',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const isBuddy = await this.core.apis.FriendApi.isBuddy(uid);
|
||||||
|
if (!isBuddy) {
|
||||||
|
return {
|
||||||
|
valid: false,
|
||||||
|
message: '不是好友',
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return await this.core.apis.FriendApi.delBuudy(uid, payload.temp_block, payload.temp_both_del);
|
||||||
|
}
|
||||||
|
}
|
28
src/onebot/action/go-cqhttp/GoCQHTTPGetModelShow.ts
Normal file
28
src/onebot/action/go-cqhttp/GoCQHTTPGetModelShow.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
model: { type: 'string' },
|
||||||
|
}
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class GoCQHTTPGetModelShow extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_GetModelShow;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
async _handle(payload: Payload) {
|
||||||
|
if (!payload.model) {
|
||||||
|
payload.model = 'napcat';
|
||||||
|
}
|
||||||
|
return [{
|
||||||
|
variants: {
|
||||||
|
model_show: "napcat",
|
||||||
|
need_pay: false
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
19
src/onebot/action/go-cqhttp/GoCQHTTPSetModelShow.ts
Normal file
19
src/onebot/action/go-cqhttp/GoCQHTTPSetModelShow.ts
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {},
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
//兼容性代码
|
||||||
|
export class GoCQHTTPSetModelShow extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GoCQHTTP_SetModelShow;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
async _handle(payload: Payload) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,10 +0,0 @@
|
|||||||
import BaseAction from '../BaseAction';
|
|
||||||
import { ActionName } from '../types';
|
|
||||||
|
|
||||||
export default class SetModelShow extends BaseAction<null, null> {
|
|
||||||
actionName = ActionName.SetModelShow;
|
|
||||||
|
|
||||||
async _handle(payload: null): Promise<null> {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -21,7 +21,14 @@ export class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
|||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const groupIdStr = payload.group_id.toString();
|
const groupIdStr = payload.group_id.toString();
|
||||||
const groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr);
|
const noCache = payload.no_cache ? this.stringToBoolean(payload.no_cache) : false;
|
||||||
|
const memberCache = this.core.apis.GroupApi.groupMemberCache;
|
||||||
|
let groupMembers;
|
||||||
|
if (noCache) {
|
||||||
|
groupMembers = await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr);
|
||||||
|
} else {
|
||||||
|
groupMembers = memberCache.get(groupIdStr) ?? await this.core.apis.GroupApi.getGroupMembersV2(groupIdStr);
|
||||||
|
}
|
||||||
|
|
||||||
const memberPromises = Array.from(groupMembers.values()).map(item =>
|
const memberPromises = Array.from(groupMembers.values()).map(item =>
|
||||||
OB11Entities.groupMember(groupIdStr, item)
|
OB11Entities.groupMember(groupIdStr, item)
|
||||||
@@ -30,4 +37,7 @@ export class GetGroupMemberList extends BaseAction<Payload, OB11GroupMember[]> {
|
|||||||
const MemberMap = new Map(_groupMembers.map(member => [member.user_id, member]));
|
const MemberMap = new Map(_groupMembers.map(member => [member.user_id, member]));
|
||||||
return Array.from(MemberMap.values());
|
return Array.from(MemberMap.values());
|
||||||
}
|
}
|
||||||
|
stringToBoolean(str: string | boolean): boolean {
|
||||||
|
return typeof str === 'boolean' ? str : str.toLowerCase() === "true";
|
||||||
|
}
|
||||||
}
|
}
|
@@ -71,7 +71,6 @@ import { FetchUserProfileLike } from './extends/FetchUserProfileLike';
|
|||||||
import { NapCatCore } from '@/core';
|
import { NapCatCore } from '@/core';
|
||||||
import { NapCatOneBot11Adapter } from '@/onebot';
|
import { NapCatOneBot11Adapter } from '@/onebot';
|
||||||
import GetGuildProfile from './guild/GetGuildProfile';
|
import GetGuildProfile from './guild/GetGuildProfile';
|
||||||
import SetModelShow from './go-cqhttp/SetModelShow';
|
|
||||||
import { SetInputStatus } from './extends/SetInputStatus';
|
import { SetInputStatus } from './extends/SetInputStatus';
|
||||||
import { GetCSRF } from './system/GetCSRF';
|
import { GetCSRF } from './system/GetCSRF';
|
||||||
import { DelGroupNotice } from './group/DelGroupNotice';
|
import { DelGroupNotice } from './group/DelGroupNotice';
|
||||||
@@ -94,6 +93,11 @@ import { GetPacketStatus } from "@/onebot/action/packet/GetPacketStatus";
|
|||||||
import { FriendPoke } from "@/onebot/action/user/FriendPoke";
|
import { FriendPoke } from "@/onebot/action/user/FriendPoke";
|
||||||
import { GetCredentials } from './system/GetCredentials';
|
import { GetCredentials } from './system/GetCredentials';
|
||||||
import { SetGroupSign } from './extends/SetGroupSign';
|
import { SetGroupSign } from './extends/SetGroupSign';
|
||||||
|
import { GoCQHTTPGetGroupAtAllRemain } from './go-cqhttp/GetGroupAtAllRemain';
|
||||||
|
import { GoCQHTTPCheckUrlSafely } from './go-cqhttp/GoCQHTTPCheckUrlSafely';
|
||||||
|
import { GoCQHTTPGetModelShow } from './go-cqhttp/GoCQHTTPGetModelShow';
|
||||||
|
import { GoCQHTTPSetModelShow } from './go-cqhttp/GoCQHTTPSetModelShow';
|
||||||
|
import { GoCQHTTPDeleteFriend } from './go-cqhttp/GoCQHTTPDeleteFriend';
|
||||||
|
|
||||||
|
|
||||||
export type ActionMap = Map<string, BaseAction<any, any>>;
|
export type ActionMap = Map<string, BaseAction<any, any>>;
|
||||||
@@ -151,6 +155,8 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
|||||||
new GetRobotUinRange(obContext, core),
|
new GetRobotUinRange(obContext, core),
|
||||||
new GetFriendWithCategory(obContext, core),
|
new GetFriendWithCategory(obContext, core),
|
||||||
//以下为go-cqhttp api
|
//以下为go-cqhttp api
|
||||||
|
new GoCQHTTPDeleteFriend(obContext, core),
|
||||||
|
new GoCQHTTPCheckUrlSafely(obContext, core),
|
||||||
new GetOnlineClient(obContext, core),
|
new GetOnlineClient(obContext, core),
|
||||||
new OCRImage(obContext, core),
|
new OCRImage(obContext, core),
|
||||||
new IOCRImage(obContext, core),
|
new IOCRImage(obContext, core),
|
||||||
@@ -158,6 +164,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
|||||||
new SendGroupNotice(obContext, core),
|
new SendGroupNotice(obContext, core),
|
||||||
new GetGroupNotice(obContext, core),
|
new GetGroupNotice(obContext, core),
|
||||||
new GetGroupEssence(obContext, core),
|
new GetGroupEssence(obContext, core),
|
||||||
|
new GoCQHTTPGetGroupAtAllRemain(obContext, core),
|
||||||
new GoCQHTTPSendForwardMsg(obContext, core),
|
new GoCQHTTPSendForwardMsg(obContext, core),
|
||||||
new GoCQHTTPSendGroupForwardMsg(obContext, core),
|
new GoCQHTTPSendGroupForwardMsg(obContext, core),
|
||||||
new GoCQHTTPSendPrivateForwardMsg(obContext, core),
|
new GoCQHTTPSendPrivateForwardMsg(obContext, core),
|
||||||
@@ -180,7 +187,9 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
|||||||
new FetchCustomFace(obContext, core),
|
new FetchCustomFace(obContext, core),
|
||||||
new GoCQHTTPUploadPrivateFile(obContext, core),
|
new GoCQHTTPUploadPrivateFile(obContext, core),
|
||||||
new GetGuildProfile(obContext, core),
|
new GetGuildProfile(obContext, core),
|
||||||
new SetModelShow(obContext, core),
|
new GoCQHTTPGetModelShow(obContext, core),
|
||||||
|
new GoCQHTTPSetModelShow(obContext, core),
|
||||||
|
new GoCQHTTPCheckUrlSafely(obContext, core),
|
||||||
new SetInputStatus(obContext, core),
|
new SetInputStatus(obContext, core),
|
||||||
new GetCSRF(obContext, core),
|
new GetCSRF(obContext, core),
|
||||||
new GetCredentials(obContext, core),
|
new GetCredentials(obContext, core),
|
||||||
|
@@ -14,6 +14,7 @@ import BaseAction from '../BaseAction';
|
|||||||
import { rawMsgWithSendMsg } from "@/core/packet/msg/converter";
|
import { rawMsgWithSendMsg } from "@/core/packet/msg/converter";
|
||||||
import { PacketMsg } from "@/core/packet/msg/message";
|
import { PacketMsg } from "@/core/packet/msg/message";
|
||||||
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
|
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
|
||||||
|
import { stringifyWithBigInt } from "@/common/helper";
|
||||||
|
|
||||||
export interface ReturnDataType {
|
export interface ReturnDataType {
|
||||||
message_id: number;
|
message_id: number;
|
||||||
@@ -116,9 +117,17 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
|
|
||||||
if (getSpecialMsgNum(payload, OB11MessageDataType.node)) {
|
if (getSpecialMsgNum(payload, OB11MessageDataType.node)) {
|
||||||
const packetMode = this.core.apis.PacketApi.available;
|
const packetMode = this.core.apis.PacketApi.available;
|
||||||
const returnMsgAndResId = packetMode
|
let returnMsgAndResId: { message: RawMessage | null, res_id?: string } | null;
|
||||||
? await this.handleForwardedNodesPacket(peer, messages as OB11MessageNode[], payload.source, payload.news, payload.summary, payload.prompt)
|
try {
|
||||||
: await this.handleForwardedNodes(peer, messages as OB11MessageNode[]);
|
returnMsgAndResId = packetMode
|
||||||
|
? await this.handleForwardedNodesPacket(peer, messages as OB11MessageNode[], payload.source, payload.news, payload.summary, payload.prompt)
|
||||||
|
: await this.handleForwardedNodes(peer, messages as OB11MessageNode[]);
|
||||||
|
} catch (e) {
|
||||||
|
throw Error(packetMode ? `发送伪造合并转发消息失败: ${e}` : `发送合并转发消息失败: ${e}`);
|
||||||
|
}
|
||||||
|
if (!returnMsgAndResId) {
|
||||||
|
throw Error('发送合并转发消息失败:returnMsgAndResId 为空!');
|
||||||
|
}
|
||||||
if (returnMsgAndResId.message) {
|
if (returnMsgAndResId.message) {
|
||||||
const msgShortId = MessageUnique.createUniqueMsgId({
|
const msgShortId = MessageUnique.createUniqueMsgId({
|
||||||
guildId: '',
|
guildId: '',
|
||||||
@@ -129,7 +138,6 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
} else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) {
|
} else if (returnMsgAndResId.res_id && !returnMsgAndResId.message) {
|
||||||
throw Error(`发送转发消息(res_id:${returnMsgAndResId.res_id} 失败`);
|
throw Error(`发送转发消息(res_id:${returnMsgAndResId.res_id} 失败`);
|
||||||
}
|
}
|
||||||
throw Error('发送转发消息失败');
|
|
||||||
} else {
|
} else {
|
||||||
// if (getSpecialMsgNum(payload, OB11MessageDataType.music)) {
|
// if (getSpecialMsgNum(payload, OB11MessageDataType.music)) {
|
||||||
// const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic;
|
// const music: OB11MessageCustomMusic = messages[0] as OB11MessageCustomMusic;
|
||||||
@@ -145,48 +153,96 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
return { message_id: returnMsg!.id! };
|
return { message_id: returnMsg!.id! };
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: recursively handle forwarded nodes
|
private async uploadForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[], source?: string, news?: {
|
||||||
private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[], source?: string, news?: { text: string }[], summary?: string, prompt?: string): Promise<{
|
text: string
|
||||||
message: RawMessage | null,
|
}[], summary?: string, prompt?: string, parentMeta?: {
|
||||||
|
user_id: string,
|
||||||
|
nickname: string,
|
||||||
|
}, dp: number = 0): Promise<{
|
||||||
|
finallySendElements: SendArkElement,
|
||||||
res_id?: string
|
res_id?: string
|
||||||
}> {
|
} | null> {
|
||||||
const logger = this.core.context.logger;
|
const logger = this.core.context.logger;
|
||||||
const packetMsg: PacketMsg[] = [];
|
const packetMsg: PacketMsg[] = [];
|
||||||
for (const node of messageNodes) {
|
for (const node of messageNodes) {
|
||||||
if ((node.data.id && typeof node.data.content !== "string") || !node.data.id) {
|
if (dp >= 3) {
|
||||||
const OB11Data = normalize(node.data.content);
|
logger.logWarn('转发消息深度超过3层,将停止解析!');
|
||||||
const { sendElements } = await this.obContext.apis.MsgApi.createSendElements(OB11Data, msgPeer);
|
break;
|
||||||
|
}
|
||||||
|
if (!node.data.id) {
|
||||||
|
const OB11Data = normalize(node.type === OB11MessageDataType.node ? node.data.content : node);
|
||||||
|
let sendElements: SendMessageElement[];
|
||||||
|
|
||||||
|
if (getSpecialMsgNum({ message: OB11Data }, OB11MessageDataType.node)) {
|
||||||
|
const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, OB11Data as OB11MessageNode[], node.data.source, node.data.news, node.data.summary, node.data.prompt, {
|
||||||
|
user_id: (node.data.user_id || node.data.uin)?.toString() ?? parentMeta?.user_id ?? this.core.selfInfo.uin,
|
||||||
|
nickname: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
|
||||||
|
}, dp + 1);
|
||||||
|
sendElements = uploadReturnData?.finallySendElements ? [uploadReturnData.finallySendElements] : [];
|
||||||
|
} else {
|
||||||
|
const sendElementsCreateReturn = await this.obContext.apis.MsgApi.createSendElements(OB11Data, msgPeer);
|
||||||
|
sendElements = sendElementsCreateReturn.sendElements;
|
||||||
|
}
|
||||||
|
|
||||||
const packetMsgElements: rawMsgWithSendMsg = {
|
const packetMsgElements: rawMsgWithSendMsg = {
|
||||||
senderUin: Number(node.data.user_id) ?? +this.core.selfInfo.uin,
|
senderUin: Number((node.data.user_id || node.data.uin) ?? parentMeta?.user_id) || +this.core.selfInfo.uin,
|
||||||
senderName: node.data.nickname,
|
senderName: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
|
||||||
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
|
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
|
||||||
time: Date.now(),
|
time: Number(node.data.time) || Date.now(),
|
||||||
msg: sendElements,
|
msg: sendElements,
|
||||||
};
|
};
|
||||||
logger.logDebug(`handleForwardedNodesPacket 开始转换 ${JSON.stringify(packetMsgElements)}`);
|
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 开始转换 ${stringifyWithBigInt(packetMsgElements)}`);
|
||||||
const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements);
|
const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgWithSendMsgToPacketMsg(packetMsgElements);
|
||||||
logger.logDebug(`handleForwardedNodesPacket 转换为 ${JSON.stringify(transformedMsg)}`);
|
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||||
|
packetMsg.push(transformedMsg!);
|
||||||
|
} else if (node.data.id) {
|
||||||
|
const id = node.data.id;
|
||||||
|
const nodeMsg = MessageUnique.getMsgIdAndPeerByShortId(+id) || MessageUnique.getPeerByMsgId(id);
|
||||||
|
if (!nodeMsg) {
|
||||||
|
logger.logError.bind(this.core.context.logger)('转发消息失败,未找到消息', id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(nodeMsg.Peer, [nodeMsg.MsgId])).msgList[0];
|
||||||
|
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 开始转换 ${stringifyWithBigInt(msg)}`);
|
||||||
|
await this.core.apis.FileApi.downloadRawMsgMedia([msg]);
|
||||||
|
const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgToPacketMsg(msg, msgPeer);
|
||||||
|
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||||
packetMsg.push(transformedMsg!);
|
packetMsg.push(transformedMsg!);
|
||||||
} else {
|
} else {
|
||||||
logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${JSON.stringify(node)}`);
|
logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${stringifyWithBigInt(node)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (packetMsg.length === 0) {
|
||||||
|
logger.logWarn('handleForwardedNodesPacket 元素为空!');
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0);
|
const resid = await this.core.apis.PacketApi.sendUploadForwardMsg(packetMsg, msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : 0);
|
||||||
const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg, source, news, summary, prompt);
|
const forwardJson = ForwardMsgBuilder.fromPacketMsg(resid, packetMsg, source, news, summary, prompt);
|
||||||
const finallySendElements = {
|
return {
|
||||||
elementType: ElementType.ARK,
|
finallySendElements: {
|
||||||
elementId: "",
|
elementType: ElementType.ARK,
|
||||||
arkElement: {
|
elementId: "",
|
||||||
bytesData: JSON.stringify(forwardJson),
|
arkElement: {
|
||||||
},
|
bytesData: JSON.stringify(forwardJson),
|
||||||
} as SendArkElement;
|
},
|
||||||
let returnMsg: RawMessage | undefined;
|
} as SendArkElement,
|
||||||
try {
|
res_id: resid,
|
||||||
returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined);
|
};
|
||||||
} catch (e) {
|
}
|
||||||
logger.logWarn("发送伪造合并转发消息失败!", e);
|
|
||||||
}
|
private async handleForwardedNodesPacket(msgPeer: Peer, messageNodes: OB11MessageNode[], source?: string, news?: {
|
||||||
return { message: returnMsg ?? null, res_id: resid };
|
text: string
|
||||||
|
}[], summary?: string, prompt?: string): Promise<{
|
||||||
|
message: RawMessage | null,
|
||||||
|
res_id?: string
|
||||||
|
}> {
|
||||||
|
let returnMsg: RawMessage | undefined, res_id: string | undefined;
|
||||||
|
const uploadReturnData = await this.uploadForwardedNodesPacket(msgPeer, messageNodes, source, news, summary, prompt);
|
||||||
|
res_id = uploadReturnData?.res_id;
|
||||||
|
const finallySendElements = uploadReturnData?.finallySendElements;
|
||||||
|
if (!finallySendElements) throw Error('转发消息失败,生成节点为空');
|
||||||
|
returnMsg = await this.obContext.apis.MsgApi.sendMsgWithOb11UniqueId(msgPeer, [finallySendElements], [], true).catch(_ => undefined);
|
||||||
|
return { message: returnMsg ?? null, res_id };
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleForwardedNodes(destPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{
|
private async handleForwardedNodes(destPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{
|
||||||
@@ -220,6 +276,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
logger.logError.bind(this.core.context.logger)('子消息中包含非node消息 跳过不合法部分');
|
logger.logError.bind(this.core.context.logger)('子消息中包含非node消息 跳过不合法部分');
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// @ts-ignore
|
||||||
const nodeMsg = await this.handleForwardedNodes(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
|
const nodeMsg = await this.handleForwardedNodes(selfPeer, OB11Data.filter(e => e.type === OB11MessageDataType.node));
|
||||||
if (nodeMsg) {
|
if (nodeMsg) {
|
||||||
nodeMsgIds.push(nodeMsg.message!.msgId);
|
nodeMsgIds.push(nodeMsg.message!.msgId);
|
||||||
|
@@ -5,16 +5,14 @@ import { ActionName, BaseCheckResult } from '../types';
|
|||||||
export abstract class GetPacketStatusDepends<PT, RT> extends BaseAction<PT, RT> {
|
export abstract class GetPacketStatusDepends<PT, RT> extends BaseAction<PT, RT> {
|
||||||
actionName = ActionName.GetPacketStatus;
|
actionName = ActionName.GetPacketStatus;
|
||||||
|
|
||||||
protected async check(): Promise<BaseCheckResult>{
|
protected async check(payload: PT): Promise<BaseCheckResult>{
|
||||||
if (!this.core.apis.PacketApi.available) {
|
if (!this.core.apis.PacketApi.available) {
|
||||||
return {
|
return {
|
||||||
valid: false,
|
valid: false,
|
||||||
message: "packetServer不可用,请参照文档 https://napneko.github.io/config/advanced 检查packetServer状态或进行配置!",
|
message: "packetServer不可用,请参照文档 https://napneko.github.io/config/advanced 检查packetServer状态或进行配置!",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {
|
return await super.check(payload);
|
||||||
valid: true,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -57,11 +57,11 @@ export enum ActionName {
|
|||||||
// go-cqhttp
|
// go-cqhttp
|
||||||
SetQQProfile = 'set_qq_profile',
|
SetQQProfile = 'set_qq_profile',
|
||||||
// QidianGetAccountInfo = 'qidian_get_account_info',
|
// QidianGetAccountInfo = 'qidian_get_account_info',
|
||||||
// GetModelShow = '_get_model_show',
|
GoCQHTTP_GetModelShow = '_get_model_show',
|
||||||
// SetModelShow = '_set_model_show',
|
GoCQHTTP_SetModelShow = '_set_model_show',
|
||||||
GetOnlineClient = 'get_online_clients',
|
GetOnlineClient = 'get_online_clients',
|
||||||
// GetUnidirectionalFriendList = 'get_unidirectional_friend_list',
|
// GetUnidirectionalFriendList = 'get_unidirectional_friend_list',
|
||||||
// DeleteFriend = 'delete_friend',
|
GoCQHTTP_DeleteFriend = 'delete_friend',
|
||||||
// DeleteUnidirectionalFriendList = 'delete_unidirectional_friend',
|
// DeleteUnidirectionalFriendList = 'delete_unidirectional_friend',
|
||||||
GoCQHTTP_MarkMsgAsRead = 'mark_msg_as_read',
|
GoCQHTTP_MarkMsgAsRead = 'mark_msg_as_read',
|
||||||
GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg',
|
GoCQHTTP_SendGroupForwardMsg = 'send_group_forward_msg',
|
||||||
@@ -71,7 +71,7 @@ export enum ActionName {
|
|||||||
IOCRImage = '.ocr_image',
|
IOCRImage = '.ocr_image',
|
||||||
GetGroupSystemMsg = 'get_group_system_msg',
|
GetGroupSystemMsg = 'get_group_system_msg',
|
||||||
GoCQHTTP_GetEssenceMsg = 'get_essence_msg_list',
|
GoCQHTTP_GetEssenceMsg = 'get_essence_msg_list',
|
||||||
// GetGroupAtAllRemain = 'get_group_at_all_remain',
|
GoCQHTTP_GetGroupAtAllRemain = 'get_group_at_all_remain',
|
||||||
SetGroupPortrait = 'set_group_portrait',
|
SetGroupPortrait = 'set_group_portrait',
|
||||||
SetEssenceMsg = 'set_essence_msg',
|
SetEssenceMsg = 'set_essence_msg',
|
||||||
DelEssenceMsg = 'delete_essence_msg',
|
DelEssenceMsg = 'delete_essence_msg',
|
||||||
@@ -88,8 +88,8 @@ export enum ActionName {
|
|||||||
GOCQHTTP_UploadPrivateFile = 'upload_private_file',
|
GOCQHTTP_UploadPrivateFile = 'upload_private_file',
|
||||||
// GOCQHTTP_ReloadEventFilter = 'reload_event_filter',
|
// GOCQHTTP_ReloadEventFilter = 'reload_event_filter',
|
||||||
GoCQHTTP_DownloadFile = 'download_file',
|
GoCQHTTP_DownloadFile = 'download_file',
|
||||||
// GoCQHTTP_CheckUrlSafely = 'check_url_safely',
|
GoCQHTTP_CheckUrlSafely = 'check_url_safely',
|
||||||
// GoCQHTTP_GetWordSlices = '.get_word_slices',
|
GoCQHTTP_GetWordSlices = '.get_word_slices',
|
||||||
GoCQHTTP_HandleQuickAction = '.handle_quick_operation',
|
GoCQHTTP_HandleQuickAction = '.handle_quick_operation',
|
||||||
|
|
||||||
// 以下为扩展napcat扩展
|
// 以下为扩展napcat扩展
|
||||||
|
@@ -120,7 +120,7 @@ export class OneBotMsgApi {
|
|||||||
url: await this.core.apis.FileApi.getImageUrl(element),
|
url: await this.core.apis.FileApi.getImageUrl(element),
|
||||||
path: element.filePath,
|
path: element.filePath,
|
||||||
file_size: element.fileSize,
|
file_size: element.fileSize,
|
||||||
file_unique: element.fileName
|
file_unique: element.md5HexStr ?? element.fileName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
@@ -141,9 +141,9 @@ export class OneBotMsgApi {
|
|||||||
file: element.fileName,
|
file: element.fileName,
|
||||||
path: element.filePath,
|
path: element.filePath,
|
||||||
url: pathToFileURL(element.filePath).href,
|
url: pathToFileURL(element.filePath).href,
|
||||||
file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid,"." + element.fileName),
|
file_id: FileNapCatOneBotUUID.encode(peer, msg.msgId, elementWrapper.elementId, element.fileUuid, "." + element.fileName),
|
||||||
file_size: element.fileSize,
|
file_size: element.fileSize,
|
||||||
file_unique: element.fileName,
|
file_unique: element.fileMd5 ?? element.fileSha ?? element.fileName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -204,7 +204,7 @@ export class OneBotMsgApi {
|
|||||||
guildId: '',
|
guildId: '',
|
||||||
};
|
};
|
||||||
if (!records || !element.replyMsgTime || !element.senderUidStr) {
|
if (!records || !element.replyMsgTime || !element.senderUidStr) {
|
||||||
this.core.context.logger.logError.bind(this.core.context.logger)('获取不到引用的消息', element.replayMsgSeq);
|
this.core.context.logger.logError.bind(this.core.context.logger)('似乎是旧版客户端,获取不到引用的消息', element.replayMsgSeq);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,11 +218,27 @@ export class OneBotMsgApi {
|
|||||||
if (records.peerUin === '284840486' || records.peerUin === '1094950020') {
|
if (records.peerUin === '284840486' || records.peerUin === '1094950020') {
|
||||||
return createReplyData(records.msgId);
|
return createReplyData(records.msgId);
|
||||||
}
|
}
|
||||||
const replyMsg = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, element.replyMsgTime, [element.senderUidStr]))
|
let replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, element.replyMsgTime, [element.senderUidStr])).msgList;
|
||||||
.msgList.find(msg => msg.msgRandom === records.msgRandom);
|
let replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
||||||
|
|
||||||
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
this.core.context.logger.logError.bind(this.core.context.logger)('获取不到引用的消息', element.replayMsgSeq);
|
// 我猜测可能是时间参数未对上 导致找不到引用消息 或者msgList 存在问题
|
||||||
|
this.core.context.logger.logWarn.bind(this.core.context.logger)(
|
||||||
|
'初次筛选消息失败,获取不到引用的消息 Seq:',
|
||||||
|
element.replayMsgSeq,
|
||||||
|
',消息长度:',
|
||||||
|
replyMsgList.length
|
||||||
|
);
|
||||||
|
// 再次筛选
|
||||||
|
replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV3(peer, element.replayMsgSeq, [element.senderUidStr])).msgList;
|
||||||
|
replyMsg = replyMsgList.find(msg => msg.msgRandom === records.msgRandom);
|
||||||
|
}
|
||||||
|
if (!replyMsg || records.msgRandom !== replyMsg.msgRandom) {
|
||||||
|
this.core.context.logger.logError.bind(this.core.context.logger)(
|
||||||
|
'最终筛选结果,筛选消息失败,获取不到引用的消息 Seq: ',
|
||||||
|
element.replayMsgSeq,
|
||||||
|
',消息长度:',
|
||||||
|
replyMsgList.length
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return createReplyData(replyMsg.msgId);
|
return createReplyData(replyMsg.msgId);
|
||||||
@@ -285,7 +301,7 @@ export class OneBotMsgApi {
|
|||||||
url: videoDownUrl ?? pathToFileURL(element.filePath).href,
|
url: videoDownUrl ?? pathToFileURL(element.filePath).href,
|
||||||
file_id: fileCode,
|
file_id: fileCode,
|
||||||
file_size: element.fileSize,
|
file_size: element.fileSize,
|
||||||
file_unique: element.fileName,
|
file_unique: element.videoMd5 ?? element.thumbMd5 ?? element.fileName,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -305,7 +321,7 @@ export class OneBotMsgApi {
|
|||||||
url: pathToFileURL(element.filePath).href,
|
url: pathToFileURL(element.filePath).href,
|
||||||
file_id: fileCode,
|
file_id: fileCode,
|
||||||
file_size: element.fileSize,
|
file_size: element.fileSize,
|
||||||
file_unique: element.fileName
|
file_unique: element.fileUuid
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -466,6 +482,7 @@ export class OneBotMsgApi {
|
|||||||
},
|
},
|
||||||
}) => ({
|
}) => ({
|
||||||
elementType: ElementType.MFACE,
|
elementType: ElementType.MFACE,
|
||||||
|
elementId: '',
|
||||||
marketFaceElement: {
|
marketFaceElement: {
|
||||||
emojiPackageId: emoji_package_id,
|
emojiPackageId: emoji_package_id,
|
||||||
emojiId: emoji_id,
|
emojiId: emoji_id,
|
||||||
@@ -625,13 +642,13 @@ export class OneBotMsgApi {
|
|||||||
[OB11MessageDataType.miniapp]: async () => undefined,
|
[OB11MessageDataType.miniapp]: async () => undefined,
|
||||||
|
|
||||||
[OB11MessageDataType.contact]: async ({ data: { type = "qq", id } }, context) => {
|
[OB11MessageDataType.contact]: async ({ data: { type = "qq", id } }, context) => {
|
||||||
if(type === "qq"){
|
if (type === "qq") {
|
||||||
const arkJson = await this.core.apis.UserApi.getBuddyRecommendContactArkJson(id.toString(), '');
|
const arkJson = await this.core.apis.UserApi.getBuddyRecommendContactArkJson(id.toString(), '');
|
||||||
return this.ob11ToRawConverters.json({
|
return this.ob11ToRawConverters.json({
|
||||||
data: { data: arkJson.arkMsg },
|
data: { data: arkJson.arkMsg },
|
||||||
type: OB11MessageDataType.json
|
type: OB11MessageDataType.json
|
||||||
}, context);
|
}, context);
|
||||||
}else if(type === "group"){
|
} else if (type === "group") {
|
||||||
const arkJson = await this.core.apis.GroupApi.getGroupRecommendContactArkJson(id.toString());
|
const arkJson = await this.core.apis.GroupApi.getGroupRecommendContactArkJson(id.toString());
|
||||||
return this.ob11ToRawConverters.json({
|
return this.ob11ToRawConverters.json({
|
||||||
data: { data: arkJson.arkJson },
|
data: { data: arkJson.arkJson },
|
||||||
|
@@ -119,11 +119,25 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
|
|||||||
|
|
||||||
async close() {
|
async close() {
|
||||||
this.isOpen = false;
|
this.isOpen = false;
|
||||||
this.wsServer.close();
|
this.wsServer.close((err) => {
|
||||||
|
if (err) {
|
||||||
|
this.logger.logError.bind(this.logger)('[OneBot] [WebSocket Server] Error closing server:', err.message);
|
||||||
|
} else {
|
||||||
|
this.logger.log.bind(this.logger)('[OneBot] [WebSocket Server] Server Closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
if (this.heartbeatIntervalId) {
|
if (this.heartbeatIntervalId) {
|
||||||
clearInterval(this.heartbeatIntervalId);
|
clearInterval(this.heartbeatIntervalId);
|
||||||
this.heartbeatIntervalId = null;
|
this.heartbeatIntervalId = null;
|
||||||
}
|
}
|
||||||
|
await this.wsClientsMutex.runExclusive(async () => {
|
||||||
|
this.wsClients.forEach((wsClient) => {
|
||||||
|
wsClient.close();
|
||||||
|
});
|
||||||
|
this.wsClients = [];
|
||||||
|
this.wsClientWithEvent = [];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private registerHeartBeat() {
|
private registerHeartBeat() {
|
||||||
|
@@ -150,8 +150,15 @@ export interface OB11MessageNode {
|
|||||||
data: {
|
data: {
|
||||||
id?: string
|
id?: string
|
||||||
user_id?: number | string // number
|
user_id?: number | string // number
|
||||||
|
uin?: number | string // number, compatible with go-cqhttp
|
||||||
nickname: string
|
nickname: string
|
||||||
|
name?: string // compatible with go-cqhttp
|
||||||
content: OB11MessageMixType
|
content: OB11MessageMixType
|
||||||
|
source?: string,
|
||||||
|
news?: { text: string }[],
|
||||||
|
summary?: string,
|
||||||
|
prompt?: string
|
||||||
|
time?: string
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,6 +232,7 @@ export interface OB11PostSendMsg {
|
|||||||
news?: { text: string }[],
|
news?: { text: string }[],
|
||||||
summary?: string,
|
summary?: string,
|
||||||
prompt?: string
|
prompt?: string
|
||||||
|
time?: string
|
||||||
}
|
}
|
||||||
export interface OB11PostContext {
|
export interface OB11PostContext {
|
||||||
message_type?: 'private' | 'group'
|
message_type?: 'private' | 'group'
|
||||||
|
@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
'<span id="napcat-update-title">Napcat</span>',
|
'<span id="napcat-update-title">Napcat</span>',
|
||||||
undefined,
|
undefined,
|
||||||
SettingButton('V3.1.6', 'napcat-update-button', 'secondary'),
|
SettingButton('V3.3.12', 'napcat-update-button', 'secondary'),
|
||||||
),
|
),
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
|
|||||||
SettingItem(
|
SettingItem(
|
||||||
'<span id="napcat-update-title">Napcat</span>',
|
'<span id="napcat-update-title">Napcat</span>',
|
||||||
void 0,
|
void 0,
|
||||||
SettingButton("V3.1.6", "napcat-update-button", "secondary")
|
SettingButton("V3.3.12", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
Reference in New Issue
Block a user