mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
cba9c78ab1 | ||
![]() |
c32db4a881 | ||
![]() |
871add3071 | ||
![]() |
e661c617a3 | ||
![]() |
d4bf721540 | ||
![]() |
d91b55faed | ||
![]() |
9687832d4d | ||
![]() |
fc3e436744 | ||
![]() |
da90245f7b | ||
![]() |
410d6a85d7 | ||
![]() |
b693342e4f |
@@ -2,8 +2,8 @@
|
|||||||
"name": "qq-chat",
|
"name": "qq-chat",
|
||||||
"version": "9.9.15-28418",
|
"version": "9.9.15-28418",
|
||||||
"verHash": "206bfa62",
|
"verHash": "206bfa62",
|
||||||
"linuxVersion": "3.2.12-28327",
|
"linuxVersion": "3.2.12-28418",
|
||||||
"linuxVerHash": "f60e8252",
|
"linuxVerHash": "0256c948",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "QQ",
|
"description": "QQ",
|
||||||
|
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "2.6.18",
|
"version": "2.6.21",
|
||||||
"icon": "./logo.png",
|
"icon": "./logo.png",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
|
105
package.json
105
package.json
@@ -1,52 +1,53 @@
|
|||||||
{
|
{
|
||||||
"name": "napcat",
|
"name": "napcat",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"version": "2.6.18",
|
"version": "2.6.21",
|
||||||
"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",
|
||||||
"build:webui": "cd ./src/webui && vite build",
|
"build:webui": "cd ./src/webui && vite build",
|
||||||
"lint": "eslint --fix src/**/*.{js,ts}",
|
"lint": "eslint --fix src/**/*.{js,ts}",
|
||||||
"depend": "cd dist && npm install --omit=dev"
|
"depend": "cd dist && npm install --omit=dev"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/preset-typescript": "^7.24.7",
|
"@babel/preset-typescript": "^7.24.7",
|
||||||
"@log4js-node/log4js-api": "^1.0.2",
|
"@log4js-node/log4js-api": "^1.0.2",
|
||||||
"@rollup/plugin-node-resolve": "^15.2.3",
|
"@protobuf-ts/runtime": "^2.9.4",
|
||||||
"@rollup/plugin-typescript": "^11.1.6",
|
"@rollup/plugin-node-resolve": "^15.2.3",
|
||||||
"@types/cors": "^2.8.17",
|
"@rollup/plugin-typescript": "^11.1.6",
|
||||||
"@types/express": "^5.0.0",
|
"@types/cors": "^2.8.17",
|
||||||
"@types/fluent-ffmpeg": "^2.1.24",
|
"@types/express": "^5.0.0",
|
||||||
"@types/node": "^22.0.1",
|
"@types/fluent-ffmpeg": "^2.1.24",
|
||||||
"@types/qrcode-terminal": "^0.12.2",
|
"@types/node": "^22.0.1",
|
||||||
"@types/ws": "^8.5.12",
|
"@types/qrcode-terminal": "^0.12.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
"@types/ws": "^8.5.12",
|
||||||
"@typescript-eslint/parser": "^8.3.0",
|
"@typescript-eslint/eslint-plugin": "^8.3.0",
|
||||||
"eslint": "^8.57.0",
|
"@typescript-eslint/parser": "^8.3.0",
|
||||||
"eslint-import-resolver-typescript": "^3.6.1",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-import": "^2.29.1",
|
"eslint-import-resolver-typescript": "^3.6.1",
|
||||||
"typescript": "^5.3.3",
|
"eslint-plugin-import": "^2.29.1",
|
||||||
"vite": "^5.2.6",
|
"typescript": "^5.3.3",
|
||||||
"vite-plugin-cp": "^4.0.8",
|
"vite": "^5.2.6",
|
||||||
"vite-tsconfig-paths": "^4.3.2"
|
"vite-plugin-cp": "^4.0.8",
|
||||||
},
|
"vite-tsconfig-paths": "^4.3.2"
|
||||||
"dependencies": {
|
},
|
||||||
"ajv": "^8.13.0",
|
"dependencies": {
|
||||||
"@protobuf-ts/plugin": "^2.9.4",
|
"ajv": "^8.13.0",
|
||||||
"async-mutex": "^0.5.0",
|
"@protobuf-ts/plugin": "^2.9.4",
|
||||||
"chalk": "^5.3.0",
|
"async-mutex": "^0.5.0",
|
||||||
"commander": "^12.1.0",
|
"chalk": "^5.3.0",
|
||||||
"cors": "^2.8.5",
|
"commander": "^12.1.0",
|
||||||
"express": "^5.0.0-beta.2",
|
"cors": "^2.8.5",
|
||||||
"fast-xml-parser": "^4.3.6",
|
"express": "^5.0.0-beta.2",
|
||||||
"file-type": "^19.0.0",
|
"fast-xml-parser": "^4.3.6",
|
||||||
"fluent-ffmpeg": "^2.1.2",
|
"file-type": "^19.0.0",
|
||||||
"image-size": "^1.1.1",
|
"fluent-ffmpeg": "^2.1.2",
|
||||||
"json-schema-to-ts": "^3.1.0",
|
"image-size": "^1.1.1",
|
||||||
"log4js": "^6.9.1",
|
"json-schema-to-ts": "^3.1.0",
|
||||||
"qrcode-terminal": "^0.12.0",
|
"log4js": "^6.9.1",
|
||||||
"silk-wasm": "^3.6.1",
|
"qrcode-terminal": "^0.12.0",
|
||||||
"ws": "^8.18.0"
|
"silk-wasm": "^3.6.1",
|
||||||
}
|
"ws": "^8.18.0"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@@ -139,8 +139,13 @@ export class LogWrapper {
|
|||||||
|
|
||||||
logMessage(msg: RawMessage, selfInfo: SelfInfo) {
|
logMessage(msg: RawMessage, selfInfo: SelfInfo) {
|
||||||
const isSelfSent = msg.senderUin === selfInfo.uin;
|
const isSelfSent = msg.senderUin === selfInfo.uin;
|
||||||
this.log(`${isSelfSent ? '发送 ->' : '接收 <-'
|
|
||||||
} ${rawMessageToText(msg)}`);
|
// Intercept grey tip
|
||||||
|
if (msg.elements[0]?.elementType === ElementType.GreyTip) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log(`${isSelfSent ? '发送 ->' : '接收 <-' } ${rawMessageToText(msg)}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +159,12 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
|
|||||||
if (msg.chatType == ChatType.KCHATTYPEC2C) {
|
if (msg.chatType == ChatType.KCHATTYPEC2C) {
|
||||||
tokens.push(`私聊 (${msg.peerUin})`);
|
tokens.push(`私聊 (${msg.peerUin})`);
|
||||||
} else if (msg.chatType == ChatType.KCHATTYPEGROUP) {
|
} else if (msg.chatType == ChatType.KCHATTYPEGROUP) {
|
||||||
tokens.push(`群聊 (群 ${msg.peerUin} 的 ${msg.senderUin})`);
|
if (recursiveLevel < 1) {
|
||||||
|
tokens.push(`群聊 [${msg.peerName}(${msg.peerUin})]`);
|
||||||
|
}
|
||||||
|
if (msg.senderUin !== '0') {
|
||||||
|
tokens.push(`[${msg.sendMemberName || msg.sendRemarkName || msg.sendNickName}(${msg.senderUin})]`);
|
||||||
|
}
|
||||||
} else if (msg.chatType == ChatType.KCHATTYPEDATALINE) {
|
} else if (msg.chatType == ChatType.KCHATTYPEDATALINE) {
|
||||||
tokens.push('移动设备');
|
tokens.push('移动设备');
|
||||||
} else /* temp */ {
|
} else /* temp */ {
|
||||||
|
@@ -1 +1 @@
|
|||||||
export const napCatVersion = '2.6.18';
|
export const napCatVersion = '2.6.21';
|
||||||
|
@@ -365,22 +365,41 @@ export class NTQQFileApi {
|
|||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);
|
const parsedUrl = new URL(IMAGE_HTTP_HOST + url);
|
||||||
|
const urlRkey = parsedUrl.searchParams.get('rkey');
|
||||||
const imageAppid = parsedUrl.searchParams.get('appid');
|
const imageAppid = parsedUrl.searchParams.get('appid');
|
||||||
const isNTV2 = imageAppid && ['1406', '1407'].includes(imageAppid);
|
const isNTV2 = imageAppid && ['1406', '1407'].includes(imageAppid);
|
||||||
if (isNTV2) {
|
const imageFileId = parsedUrl.searchParams.get('fileid');
|
||||||
let rkey = parsedUrl.searchParams.get('rkey');
|
|
||||||
if (rkey) {
|
let rkeyData = {
|
||||||
return IMAGE_HTTP_HOST_NT + url;
|
private_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qEc3Rbib9LP4',
|
||||||
}
|
group_rkey: 'CAQSKAB6JWENi5LM_xp9vumLbuThJSaYf-yzMrbZsuq7Uz2qffcqm614gds',
|
||||||
const rkeyData = await this.rkeyManager.getRkey();
|
online_rkey: false
|
||||||
rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
};
|
||||||
return IMAGE_HTTP_HOST_NT + url + `${rkey}`;
|
|
||||||
} else {
|
try {
|
||||||
return IMAGE_HTTP_HOST + url;
|
let tempRkeyData = await this.rkeyManager.getRkey();
|
||||||
|
rkeyData.group_rkey = tempRkeyData.group_rkey;
|
||||||
|
rkeyData.private_rkey = tempRkeyData.private_rkey;
|
||||||
|
rkeyData.online_rkey = tempRkeyData.expired_time > Date.now() / 1000;
|
||||||
|
} catch (e) {
|
||||||
|
this.context.logger.logError.bind(this.context.logger)('获取rkey失败 Fallback Old Mode', e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (isNTV2 && urlRkey) {
|
||||||
|
return IMAGE_HTTP_HOST_NT + urlRkey;
|
||||||
|
} else if (isNTV2 && rkeyData.online_rkey) {
|
||||||
|
let rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||||
|
return IMAGE_HTTP_HOST_NT + url + `&rkey=${rkey}`;
|
||||||
|
} else if (isNTV2 && imageFileId) {
|
||||||
|
let rkey = imageAppid === '1406' ? rkeyData.private_rkey : rkeyData.group_rkey;
|
||||||
|
return IMAGE_HTTP_HOST + `/download?appid=${imageAppid}&fileid=${imageFileId}&rkey=${rkey}`;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (fileMd5 || md5HexStr) {
|
} else if (fileMd5 || md5HexStr) {
|
||||||
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 ?? md5HexStr)!.toUpperCase()}/0`;
|
return `${IMAGE_HTTP_HOST}/gchatpic_new/0/0-0-${(fileMd5 ?? md5HexStr)!.toUpperCase()}/0`;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.context.logger.logDebug('图片url获取失败', element);
|
this.context.logger.logDebug('图片url获取失败', element);
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
@@ -909,11 +909,26 @@ export interface RawMessage {
|
|||||||
*/
|
*/
|
||||||
peerUin: string;
|
peerUin: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 好友备注(如果是好友消息)
|
||||||
|
*/
|
||||||
|
remark?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 群名(如果是群消息)
|
||||||
|
*/
|
||||||
|
peerName: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送者昵称(如果是好友消息)
|
* 发送者昵称(如果是好友消息)
|
||||||
*/
|
*/
|
||||||
sendNickName: string;
|
sendNickName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送者好友备注(如果是群消息并且有发送者好友)
|
||||||
|
*/
|
||||||
|
sendRemarkName: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 发送者群名片(如果是群消息)
|
* 发送者群名片(如果是群消息)
|
||||||
*/
|
*/
|
||||||
@@ -974,4 +989,4 @@ export interface MsgReqType {
|
|||||||
extraCnt: number
|
extraCnt: number
|
||||||
}
|
}
|
||||||
//getMsgsIncludeSelf Peer必须 byType 1
|
//getMsgsIncludeSelf Peer必须 byType 1
|
||||||
//getMsgsWithMsgTimeAndClientSeqForC2C Peer必须 byType 3
|
//getMsgsWithMsgTimeAndClientSeqForC2C Peer必须 byType 3
|
||||||
|
10
src/core/external/appid.json
vendored
10
src/core/external/appid.json
vendored
@@ -15,6 +15,10 @@
|
|||||||
"appid": 537246140,
|
"appid": 537246140,
|
||||||
"qua": "V1_LNX_NQ_3.2.12_28131_GW_B"
|
"qua": "V1_LNX_NQ_3.2.12_28131_GW_B"
|
||||||
},
|
},
|
||||||
|
"6.9.55-28131": {
|
||||||
|
"appid": 537246115,
|
||||||
|
"qua": "V1_MAC_NQ_6.9.55_28131_GW_B"
|
||||||
|
},
|
||||||
"9.9.15-28327":{
|
"9.9.15-28327":{
|
||||||
"appid": 537249321,
|
"appid": 537249321,
|
||||||
"qua": "V1_WIN_NQ_9.9.15_28327_GW_B"
|
"qua": "V1_WIN_NQ_9.9.15_28327_GW_B"
|
||||||
@@ -30,5 +34,9 @@
|
|||||||
"3.2.12-28418":{
|
"3.2.12-28418":{
|
||||||
"appid": 537249393,
|
"appid": 537249393,
|
||||||
"qua": "V1_LNX_NQ_3.2.12_28418_GW_B"
|
"qua": "V1_LNX_NQ_3.2.12_28418_GW_B"
|
||||||
|
},
|
||||||
|
"6.9.56-28418": {
|
||||||
|
"appid": 537249367,
|
||||||
|
"qua": "V1_MAC_NQ_6.9.56_28418_GW_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,8 @@ export class RkeyManager {
|
|||||||
try {
|
try {
|
||||||
await this.refreshRkey();
|
await this.refreshRkey();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.logError.bind(this.logger)('获取rkey失败', e);
|
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||||
|
//this.logger.logError.bind(this.logger)('获取rkey失败', e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return this.rkeyData;
|
return this.rkeyData;
|
||||||
@@ -42,9 +43,18 @@ export class RkeyManager {
|
|||||||
//刷新rkey
|
//刷新rkey
|
||||||
for (const url of this.serverUrl) {
|
for (const url of this.serverUrl) {
|
||||||
try {
|
try {
|
||||||
this.rkeyData = await RequestUtil.HttpGetJson<ServerRkeyData>(url, 'GET');
|
let temp = await RequestUtil.HttpGetJson<ServerRkeyData>(url, 'GET');
|
||||||
|
this.rkeyData = {
|
||||||
|
group_rkey: temp.group_rkey.slice(6),
|
||||||
|
private_rkey: temp.private_rkey.slice(6),
|
||||||
|
expired_time: temp.expired_time
|
||||||
|
};
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this.logger.logError.bind(this.logger)(`[Rkey] Get Rkey ${url} Error `, e);
|
this.logger.logError.bind(this.logger)(`[Rkey] Get Rkey ${url} Error `, e);
|
||||||
|
//是否为最后一个url
|
||||||
|
if (url === this.serverUrl[this.serverUrl.length - 1]) {
|
||||||
|
throw new Error(`获取rkey失败: ${e}`);//外抛
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/core/proto/ImageFileId.ts
Normal file
21
src/core/proto/ImageFileId.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { MessageType, BinaryReader, ScalarType, BinaryWriter } from '@protobuf-ts/runtime';
|
||||||
|
|
||||||
|
export const FileId = new MessageType("FileId", [
|
||||||
|
{ no: 2, name: "sha1", kind: "scalar", T: ScalarType.BYTES },
|
||||||
|
{ no: 4, name: "appid", kind: "scalar", T: ScalarType.UINT32 },
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function encodePBFileId(message: any) {
|
||||||
|
return FileId.internalBinaryWrite(message, new BinaryWriter(), {
|
||||||
|
writerFactory: () => new BinaryWriter(),
|
||||||
|
writeUnknownFields: false
|
||||||
|
}).finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function decodePBFileId(buffer: Uint8Array): any {
|
||||||
|
const reader = new BinaryReader(buffer);
|
||||||
|
return FileId.internalBinaryRead(reader, reader.len, {
|
||||||
|
readUnknownField: true,
|
||||||
|
readerFactory: () => new BinaryReader(buffer)
|
||||||
|
});
|
||||||
|
}
|
@@ -1,59 +1,58 @@
|
|||||||
import { MessageType, BinaryReader, ScalarType, RepeatType } from '@protobuf-ts/runtime';
|
import { MessageType, BinaryReader, ScalarType, RepeatType } from '@protobuf-ts/runtime';
|
||||||
|
|
||||||
export const LikeDetailType = new MessageType("LikeDetailType", [
|
export const LikeDetail = new MessageType("likeDetail", [
|
||||||
{ no: 1, name: "txt", kind: "scalar", T: ScalarType.STRING /* string */ },
|
{ no: 1, name: "txt", kind: "scalar", T: ScalarType.STRING /* string */ },
|
||||||
{ no: 2, name: "uin", kind: "scalar", T: ScalarType.INT64 /* int64 */ },
|
{ no: 3, name: "uin", kind: "scalar", T: ScalarType.INT64 /* int64 */ },
|
||||||
{ no: 3, name: "nickname", kind: "scalar", T: ScalarType.STRING /* string */ }
|
{ no: 5, name: "nickname", kind: "scalar", T: ScalarType.STRING /* string */ }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const LikeMsgType = new MessageType("LikeMsgType", [
|
export const LikeMsg = new MessageType("likeMsg", [
|
||||||
{ no: 1, name: "times", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
{ no: 1, name: "times", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
||||||
{ no: 2, name: "time", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
{ no: 2, name: "time", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
||||||
{ no: 3, name: "detail", kind: "message", T: () => LikeDetailType }
|
{ no: 3, name: "detail", kind: "message", T: () => LikeDetail }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const ProfileLikeSubTipType = new MessageType("ProfileLikeSubTipType", [
|
export const ProfileLikeSubTip = new MessageType("profileLikeSubTip", [
|
||||||
{ no: 1, name: "msg", kind: "message", T: () => LikeMsgType }
|
{ no: 14, name: "msg", kind: "message", T: () => LikeMsg }
|
||||||
]);
|
]);
|
||||||
|
export const ProfileLikeTip = new MessageType("profileLikeTip", [
|
||||||
export const ProfileLikeTipType = new MessageType("ProfileLikeTipType", [
|
|
||||||
{ no: 1, name: "msgType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
{ no: 1, name: "msgType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
||||||
{ no: 2, name: "subType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
{ no: 2, name: "subType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
||||||
{ no: 3, name: "content", kind: "message", T: () => ProfileLikeSubTipType }
|
{ no: 203, name: "content", kind: "message", T: () => ProfileLikeSubTip }
|
||||||
|
]);
|
||||||
|
export const SysMessageHeader = new MessageType("SysMessageHeader", [
|
||||||
|
{ no: 1, name: "PeerNumber", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
|
{ no: 2, name: "PeerString", kind: "scalar", T: ScalarType.STRING /* string */ },
|
||||||
|
{ no: 5, name: "Uin", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
|
{ no: 6, name: "Uid", kind: "scalar", T: ScalarType.STRING /* string */, opt: true }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const SysMessageHeaderType = new MessageType("SysMessageHeaderType", [
|
export const SysMessageMsgSpec = new MessageType("SysMessageMsgSpec", [
|
||||||
{ no: 1, name: "id", kind: "scalar", T: ScalarType.STRING /* string */ },
|
{ no: 1, name: "msgType", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
{ no: 2, name: "timestamp", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
{ no: 2, name: "subType", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
{ no: 3, name: "sender", kind: "scalar", T: ScalarType.STRING /* string */ }
|
{ no: 3, name: "subSubType", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
|
{ no: 5, name: "msgSeq", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
|
{ no: 6, name: "time", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ },
|
||||||
|
{ no: 12, name: "msgId", kind: "scalar", T: ScalarType.UINT64 /* uint64 */ },
|
||||||
|
{ no: 13, name: "other", kind: "scalar", T: ScalarType.UINT32 /* uint32 */ }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const SysMessageMsgSpecType = new MessageType("SysMessageMsgSpecType", [
|
export const SysMessageBodyWrapper = new MessageType("SysMessageBodyWrapper", [
|
||||||
{ no: 1, name: "msgType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
{ no: 2, name: "wrappedBody", kind: "scalar", T: ScalarType.BYTES /* bytes */ }
|
||||||
{ no: 2, name: "subType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
|
||||||
{ no: 3, name: "subSubType", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
|
||||||
{ no: 4, name: "msgSeq", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
|
||||||
{ no: 5, name: "time", kind: "scalar", T: ScalarType.INT32 /* int32 */ },
|
|
||||||
{ no: 6, name: "msgId", kind: "scalar", T: ScalarType.INT64 /* int64 */ },
|
|
||||||
{ no: 7, name: "other", kind: "scalar", T: ScalarType.INT32 /* int32 */ }
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const SysMessageBodyWrapperType = new MessageType("SysMessageBodyWrapperType", [
|
export const SysMessage = new MessageType("SysMessage", [
|
||||||
{ no: 1, name: "wrappedBody", kind: "scalar", T: ScalarType.BYTES /* bytes */ }
|
{ no: 1, name: "header", kind: "message", T: () => SysMessageHeader, repeat: RepeatType.UNPACKED },
|
||||||
]);
|
{ no: 2, name: "msgSpec", kind: "message", T: () => SysMessageMsgSpec, repeat: RepeatType.UNPACKED },
|
||||||
|
{ no: 3, name: "bodyWrapper", kind: "message", T: () => SysMessageBodyWrapper }
|
||||||
export const SysMessageType = new MessageType("SysMessageType", [
|
|
||||||
{ no: 1, name: "header", kind: "message", T: () => SysMessageHeaderType, repeat: RepeatType.PACKED },
|
|
||||||
{ no: 2, name: "msgSpec", kind: "message", T: () => SysMessageMsgSpecType, repeat: RepeatType.PACKED },
|
|
||||||
{ no: 3, name: "bodyWrapper", kind: "message", T: () => SysMessageBodyWrapperType }
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export function decodeProfileLikeTip(buffer: Uint8Array): any {
|
export function decodeProfileLikeTip(buffer: Uint8Array): any {
|
||||||
const reader = new BinaryReader(buffer);
|
const reader = new BinaryReader(buffer);
|
||||||
return ProfileLikeTipType.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) });
|
return ProfileLikeTip.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decodeSysMessage(buffer: Uint8Array): any {
|
export function decodeSysMessage(buffer: Uint8Array): any {
|
||||||
const reader = new BinaryReader(buffer);
|
const reader = new BinaryReader(buffer);
|
||||||
return SysMessageType.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) });
|
return SysMessage.internalBinaryRead(reader, reader.len, { readUnknownField: true, readerFactory: () => new BinaryReader(buffer) });
|
||||||
}
|
}
|
@@ -7,21 +7,28 @@ export class Native {
|
|||||||
supportedPlatforms = ['win32'];
|
supportedPlatforms = ['win32'];
|
||||||
MoeHooExport: any = { exports: {} };
|
MoeHooExport: any = { exports: {} };
|
||||||
recallHookEnabled: boolean = false;
|
recallHookEnabled: boolean = false;
|
||||||
|
inited = true;
|
||||||
constructor(nodePath: string, platform: string = process.platform) {
|
constructor(nodePath: string, platform: string = process.platform) {
|
||||||
this.platform = platform;
|
this.platform = platform;
|
||||||
if (!this.supportedPlatforms.includes(this.platform)) {
|
try {
|
||||||
throw new Error(`Platform ${this.platform} is not supported`);
|
if (!this.supportedPlatforms.includes(this.platform)) {
|
||||||
}
|
throw new Error(`Platform ${this.platform} is not supported`);
|
||||||
let nativeNode = path.join(nodePath, './native/MoeHoo.win32.node');
|
}
|
||||||
if (fs.existsSync(nativeNode)) {
|
let nativeNode = path.join(nodePath, './native/MoeHoo.win32.node');
|
||||||
dlopen(this.MoeHooExport, nativeNode, constants.dlopen.RTLD_LAZY);
|
if (fs.existsSync(nativeNode)) {
|
||||||
|
dlopen(this.MoeHooExport, nativeNode, constants.dlopen.RTLD_LAZY);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.inited = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
isSetReCallEnabled(): boolean {
|
isSetReCallEnabled(): boolean {
|
||||||
return this.recallHookEnabled;
|
return this.recallHookEnabled && this.inited;
|
||||||
}
|
}
|
||||||
registerRecallCallback(callback: (hex: string) => any): void {
|
registerRecallCallback(callback: (hex: string) => any): void {
|
||||||
try {
|
try {
|
||||||
|
if (!this.inited) throw new Error('Native Not Init');
|
||||||
if (this.MoeHooExport.exports?.registMsgPush) {
|
if (this.MoeHooExport.exports?.registMsgPush) {
|
||||||
this.MoeHooExport.exports.registMsgPush(callback);
|
this.MoeHooExport.exports.registMsgPush(callback);
|
||||||
this.recallHookEnabled = true;
|
this.recallHookEnabled = true;
|
||||||
|
@@ -73,53 +73,40 @@ export class NapCatOneBot11Adapter {
|
|||||||
};
|
};
|
||||||
this.actions = createActionMap(this, core);
|
this.actions = createActionMap(this, core);
|
||||||
this.networkManager = new OB11NetworkManager();
|
this.networkManager = new OB11NetworkManager();
|
||||||
this.registerNative(core, context).then().catch();
|
this.registerNative(core, context).catch(e => this.context.logger.logWarn.bind(this.context.logger)('初始化Native失败', e)).then();
|
||||||
this.InitOneBot()
|
this.InitOneBot()
|
||||||
.catch(e => this.context.logger.logError.bind(this.context.logger)('初始化OneBot失败', e));
|
.catch(e => this.context.logger.logError.bind(this.context.logger)('初始化OneBot失败', e));
|
||||||
|
|
||||||
}
|
}
|
||||||
async registerNative(core: NapCatCore, context: InstanceContext) {
|
async registerNative(core: NapCatCore, context: InstanceContext) {
|
||||||
this.nativeCore = new Native(context.pathWrapper.binaryPath);
|
try {
|
||||||
this.nativeCore.registerRecallCallback(async (hex: string) => {
|
this.nativeCore = new Native(context.pathWrapper.binaryPath);
|
||||||
try {
|
if (!this.nativeCore.inited) throw new Error('Native Not Init');
|
||||||
let data = decodeMessage(Buffer.from(hex, 'hex')) as any;
|
this.nativeCore.registerRecallCallback(async (hex: string) => {
|
||||||
//data.MsgHead.BodyInner.MsgType SubType
|
try {
|
||||||
let bodyInner = data.msgHead?.bodyInner;
|
let data = decodeMessage(Buffer.from(hex, 'hex')) as any;
|
||||||
//context.logger.log("[appNative] Parse MsgType:" + bodyInner.msgType + " / SubType:" + bodyInner.subType);
|
//data.MsgHead.BodyInner.MsgType SubType
|
||||||
if (bodyInner && bodyInner.msgType == 732 && bodyInner.subType == 17) {
|
let bodyInner = data.msgHead?.bodyInner;
|
||||||
let RecallData = Buffer.from(data.msgHead.noifyData.innerData);
|
//context.logger.log("[appNative] Parse MsgType:" + bodyInner.msgType + " / SubType:" + bodyInner.subType);
|
||||||
//跳过 4字节 群号 + 不知道的1字节 +2字节 长度
|
if (bodyInner && bodyInner.msgType == 732 && bodyInner.subType == 17) {
|
||||||
let uid = RecallData.readUint32BE();
|
let RecallData = Buffer.from(data.msgHead.noifyData.innerData);
|
||||||
const buffer = Buffer.from(RecallData.toString('hex').slice(14), 'hex');
|
//跳过 4字节 群号 + 不知道的1字节 +2字节 长度
|
||||||
let seq: number = decodeRecallGroup(buffer).recallDetails.subDetail.msgSeq;
|
let uid = RecallData.readUint32BE();
|
||||||
let peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: uid.toString() };
|
const buffer = Buffer.from(RecallData.toString('hex').slice(14), 'hex');
|
||||||
context.logger.log("[Native] 群消息撤回 Peer: " + uid.toString() + " / MsgSeq:" + seq);
|
let seq: number = decodeRecallGroup(buffer).recallDetails.subDetail.msgSeq;
|
||||||
let msgs = await core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, seq.toString());
|
let peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: uid.toString() };
|
||||||
this.recallMsgCache.put(msgs.msgList[0].msgId, msgs.msgList[0]);
|
context.logger.log("[Native] 群消息撤回 Peer: " + uid.toString() + " / MsgSeq:" + seq);
|
||||||
// let ob11 = await this.apis.MsgApi.parseMessage(msgs.msgList[0], 'array')
|
let msgs = await core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, seq.toString());
|
||||||
// .catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
|
this.recallMsgCache.put(msgs.msgList[0].msgId, msgs.msgList[0]);
|
||||||
// if (ob11) {
|
}
|
||||||
// const { sendElements, deleteAfterSentFiles } = await this.apis.MsgApi.createSendElements(ob11.message as OB11MessageData[], peer);
|
} catch (error: any) {
|
||||||
// this.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles);
|
context.logger.logWarn("[Native] Error:", (error as Error).message, ' HEX:', hex);
|
||||||
// }
|
|
||||||
|
|
||||||
|
|
||||||
// this.apis.MsgApi.sendMsg(peer, [{
|
|
||||||
// elementType: 1,
|
|
||||||
// elementId: '',
|
|
||||||
// textElement: {
|
|
||||||
// content: "[Native] 群消息撤回 Peer: " + uid.toString() + " / MsgSeq:" + seq,
|
|
||||||
// atType: 0,
|
|
||||||
// atUid: '',
|
|
||||||
// atTinyId: '',
|
|
||||||
// atNtUid: '',
|
|
||||||
// },
|
|
||||||
// }]);
|
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
});
|
||||||
context.logger.logWarn("[Native] Error:", (error as Error).message, ' HEX:', hex);
|
} catch (error) {
|
||||||
}
|
context.logger.logWarn("[Native] Error:", (error as Error).message);
|
||||||
});
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async InitOneBot() {
|
async InitOneBot() {
|
||||||
const selfInfo = this.core.selfInfo;
|
const selfInfo = this.core.selfInfo;
|
||||||
|
@@ -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('V2.6.18', 'napcat-update-button', 'secondary'),
|
SettingButton('V2.6.21', '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("V2.6.18", "napcat-update-button", "secondary")
|
SettingButton("V2.6.21", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
Reference in New Issue
Block a user