Compare commits

...

36 Commits

Author SHA1 Message Date
手瓜一十雪
c37c364a08 release: 2.6.16 2024-09-28 21:37:38 +08:00
手瓜一十雪
331a106e9a Merge branch 'hook' of https://github.com/NapNeko/NapCatQQ into hook 2024-09-28 21:37:17 +08:00
手瓜一十雪
cd74687b7b fix: getMsg 2024-09-28 21:36:54 +08:00
Alen
b3e145c1e6 fix: 解析增加字段 2024-09-28 21:29:18 +08:00
Alen
d8e1547736 Merge pull request #414 from NapNeko/hook_test
fix: 撤回SEQ
2024-09-28 21:00:32 +08:00
Alen
8617f01924 fix: 撤回SEQ 2024-09-28 20:58:09 +08:00
手瓜一十雪
55f9e75e6a Merge branch 'main' into hook 2024-09-28 20:17:02 +08:00
手瓜一十雪
b93e7b7ed1 feat: get pskey 2024-09-28 20:16:47 +08:00
手瓜一十雪
89cc79ad60 fix 2024-09-28 19:08:18 +08:00
手瓜一十雪
8dd0e60eea fix 2024-09-28 19:04:11 +08:00
手瓜一十雪
df6113fdf6 fix:#如好 2024-09-28 17:38:26 +08:00
手瓜一十雪
3a3095d15a feat:28418 2024-09-28 17:13:06 +08:00
手瓜一十雪
fb4d07391e Hook: GroupRecall 2024-09-28 15:41:11 +08:00
手瓜一十雪
9bef9c85cf fix 2024-09-28 15:36:25 +08:00
Alen
b77b3f227f Merge pull request #411 from cnxysoft/upmain
chore: qqnt.json增加linux版本
2024-09-28 14:25:42 +08:00
Alen
6a065f0a34 Merge branch 'main' into upmain 2024-09-28 14:22:10 +08:00
手瓜一十雪
4e1e190797 Merge pull request #409 from Zengfanqiang06/patch-1
Update README.md
2024-09-28 13:28:58 +08:00
手瓜一十雪
1ce8cd2100 napcat native 2024-09-28 13:27:13 +08:00
Alen
c03af6b9ad Merge branch 'main' into upmain 2024-09-28 13:24:47 +08:00
Alen
adca850075 chore: 增加linux目标QQ版本配置 2024-09-28 13:20:19 +08:00
Qiao
e3616b484e Update README.md
删除句号让其更统一(
2024-09-28 13:05:03 +08:00
手瓜一十雪
cfd7808169 Merge pull request #404 from NapNeko/dependabot/npm_and_yarn/types/express-5.0.0
chore(deps-dev): bump @types/express from 4.17.21 to 5.0.0
2024-09-27 17:08:57 +08:00
手瓜一十雪
addcedc588 Merge pull request #402 from NapNeko/v3
[Refactor] 推进版本重构
2024-09-27 16:47:48 +08:00
Alen
bfea786088 Merge pull request #405 from cnxysoft/upmain
chore: Once去除LL默认config
2024-09-26 17:21:31 +08:00
手瓜一十雪
50e84c3c9e Revert "feat: FrameWork调整"
This reverts commit 652fe8d21e.
2024-09-26 17:01:18 +08:00
手瓜一十雪
dc92ace85e Revert "feat: 调整"
This reverts commit 1a543928b1.
2024-09-26 17:01:13 +08:00
手瓜一十雪
1a543928b1 feat: 调整 2024-09-26 16:33:04 +08:00
手瓜一十雪
652fe8d21e feat: FrameWork调整 2024-09-26 16:22:21 +08:00
dependabot[bot]
199690f45f chore(deps-dev): bump @types/express from 4.17.21 to 5.0.0
Bumps [@types/express](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/express) from 4.17.21 to 5.0.0.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/express)

---
updated-dependencies:
- dependency-name: "@types/express"
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-26 08:20:36 +00:00
Alen
37a4dd4b00 chore: Once去除LL默认config 2024-09-26 16:16:46 +08:00
手瓜一十雪
34d4358bfc feat: 依赖简化 2024-09-26 16:10:52 +08:00
手瓜一十雪
90906b9019 style: lint 2024-09-26 16:08:50 +08:00
手瓜一十雪
1c212ff2b4 feat: new 2024-09-26 15:54:24 +08:00
手瓜一十雪
7d709f44a8 fix: 调整逻辑 2024-09-26 15:37:07 +08:00
手瓜一十雪
ea9e88a18a fix: 不可抗力 2024-09-26 15:31:50 +08:00
Alen
0be8a9c805 chore: 拉高目标QQ版本 2024-09-26 13:00:49 +08:00
24 changed files with 224 additions and 89 deletions

View File

@@ -4,7 +4,7 @@
---
## 欢迎回来
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
## 猫猫技能
- [x] **高性能**1K+ 群聊数目、20 线程并行发送消息毫无压力
@@ -20,7 +20,7 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
可前往 [Release](https://github.com/NapNeko/NapCatQQ/releases/) 页面下载最新版本
**首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程
**首次使用**请务必前往[官方文档](https://napneko.github.io/)查看使用教程
## 回家旅途
[QQ Group](https://qm.qq.com/q/VfjAq5HIMS)
@@ -40,4 +40,4 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
> [!CAUTION]\
> **请不要在 QQ 官方群聊和任何影响力较大的简中互联网平台(包括但不限于: 哔哩哔哩,微博,知乎,抖音等)发布和讨论*任何*与本项目存在相关性的信息**
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。**
任何使用本仓库代码的地方,都应当严格遵守[本仓库开源许可](./LICENSE)。**此外,禁止任何项目未经授权二次分发或基于 NapCat 代码开发。**

Binary file not shown.

View File

@@ -1,7 +1,9 @@
{
"name": "qq-chat",
"version": "9.9.15-28131",
"verHash": "0f14ef6e",
"version": "9.9.15-28418",
"verHash": "512caf78",
"linuxVersion": "3.2.12-28327",
"linuxVerHash": "f60e8252",
"type": "module",
"private": true,
"description": "QQ",
@@ -16,7 +18,7 @@
"qd": "externals/devtools/cli/index.js"
},
"main": "./loadNapCat.js",
"buildVersion": "28131",
"buildVersion": "28418",
"isPureShell": true,
"isByteCodeShell": true,
"platform": "win32",

View File

@@ -4,7 +4,7 @@
"name": "NapCatQQ",
"slug": "NapCat.Framework",
"description": "高性能的 OneBot 11 协议实现",
"version": "2.6.15",
"version": "2.6.16",
"icon": "./logo.png",
"authors": [
{

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "2.6.15",
"version": "2.6.16",
"scripts": {
"build:framework": "vite build --mode framework",
"build:shell": "vite build --mode shell",
@@ -17,7 +17,7 @@
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-typescript": "^11.1.6",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
"@types/express": "^5.0.0",
"@types/fluent-ffmpeg": "^2.1.24",
"@types/node": "^22.0.1",
"@types/qrcode-terminal": "^0.12.2",
@@ -30,7 +30,6 @@
"typescript": "^5.3.3",
"vite": "^5.2.6",
"vite-plugin-cp": "^4.0.8",
"vite-plugin-dts": "^3.8.2",
"vite-tsconfig-paths": "^4.3.2"
},
"dependencies": {
@@ -49,7 +48,6 @@
"protobufjs": "~7.4.0",
"qrcode-terminal": "^0.12.0",
"silk-wasm": "^3.6.1",
"strtok3": "8.0.1",
"ws": "^8.18.0"
}
}

View File

@@ -139,8 +139,7 @@ export class LogWrapper {
logMessage(msg: RawMessage, selfInfo: SelfInfo) {
const isSelfSent = msg.senderUin === selfInfo.uin;
this.log(`${
isSelfSent ? '发送 ->' : '接收 <-'
this.log(`${isSelfSent ? '发送 ->' : '接收 <-'
} ${rawMessageToText(msg)}`);
}
}
@@ -180,12 +179,11 @@ export function rawMessageToText(msg: RawMessage, recursiveLevel = 0): string {
const recordMsgOrNull = msg.records.find(
record => element.replyElement!.sourceMsgIdInRecords === record.msgId,
);
return `[回复消息 ${
recordMsgOrNull &&
recordMsgOrNull.peerUin != '284840486' // 非转发消息; 否则定位不到
?
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
`未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})`
return `[回复消息 ${recordMsgOrNull &&
recordMsgOrNull.peerUin != '284840486' && recordMsgOrNull.peerUin != '1094950020'// 非转发消息; 否则定位不到
?
rawMessageToText(recordMsgOrNull, recursiveLevel + 1) :
`未找到消息记录 (MsgId = ${element.replyElement.sourceMsgIdInRecords})`
}]`;
}

View File

@@ -1 +1 @@
export const napCatVersion = '2.6.15';
export const napCatVersion = '2.6.16';

View File

@@ -120,12 +120,20 @@ export class NTQQUserApi {
return this.context.session.getProfileService().modifyDesktopMiniProfile(param);
}
//需要异常处理
async getCookies(domain: string) {
const ClientKeyData = await this.forceFetchClientKey();
const requestUrl = 'https://ssl.ptlogin2.qq.com/jump?ptlang=1033&clientuin=' + this.core.selfInfo.uin +
'&clientkey=' + ClientKeyData.clientKey + '&u1=https%3A%2F%2F' + domain + '%2F' + this.core.selfInfo.uin + '%2Finfocenter&keyindex=19%27';
return await RequestUtil.HttpsGetCookies(requestUrl);
let data = await RequestUtil.HttpsGetCookies(requestUrl);
if (!data.p_skey || data.p_skey.length == 0) {
try {
let pskey = (await this.getPSkey([domain])).domainPskeyMap.get(domain);
if (pskey) data.p_skey = pskey;
} catch {
return data;
}
}
return data;
}
async getPSkey(domainList: string[]) {

View File

@@ -659,7 +659,8 @@ export interface GrayTipElement {
export enum FaceType {
normal = 1, // 小黄脸
normal2 = 2, // 新小黄脸, 从faceIndex 222开始
dice = 3 // 骰子
dice = 3, // 骰子
poke = 5 // 拍一拍
}
export enum FaceIndex {

View File

@@ -22,5 +22,13 @@
"3.2.12-28327":{
"appid": 537249393,
"qua": "V1_LNX_NQ_3.2.12_28327_GW_B"
},
"9.9.15-28418":{
"appid": 537249321,
"qua": "V1_WIN_NQ_9.9.15_28418_GW_B"
},
"3.2.12-28418":{
"appid": 537249393,
"qua": "V1_LNX_NQ_3.2.12_28418_GW_B"
}
}

View File

@@ -20,16 +20,15 @@ import { LogLevel, LogWrapper } from '@/common/log';
import { NodeIKernelLoginService } from '@/core/services';
import { QQBasicInfoWrapper } from '@/common/qq-basic-info';
import { NapCatPathWrapper } from '@/common/path';
import path from 'node:path';
import path, { resolve } from 'node:path';
import fs from 'node:fs';
import { hostname, systemName, systemVersion } from '@/common/system';
import { NTEventWrapper } from '@/common/event';
import { DataSource, GroupMember, KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/entities';
import { ChatType, DataSource, GroupMember, KickedOffLineInfo, Peer, SelfInfo, SelfStatusInfo } from '@/core/entities';
import { NapCatConfigLoader } from '@/core/helper/config';
import os from 'node:os';
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
import { proxiedListenerOf } from '@/common/proxy-handler';
export * from './wrapper';
export * from './entities';
export * from './services';
@@ -99,6 +98,7 @@ export class NapCatCore {
if (!fs.existsSync(this.NapCatTempPath)) {
fs.mkdirSync(this.NapCatTempPath, { recursive: true });
}
this.initNapCatCoreListeners().then().catch(this.context.logger.logError.bind(this.context.logger));
this.context.logger.setFileLogEnabled(
@@ -248,7 +248,7 @@ export class NapCatCore {
}
export async function genSessionConfig(
guid:string,
guid: string,
QQVersionAppid: string,
QQVersion: string,
selfUin: string,

37
src/core/proto/Message.ts Normal file
View File

@@ -0,0 +1,37 @@
import * as pb from 'protobufjs';
export const BodyInner = new pb.Type("BodyInner")
.add(new pb.Field("msgType", 1, "uint32", "optional"))
.add(new pb.Field("subType", 2, "uint32", "optional"))
export const NoifyData = new pb.Type("NoifyData")
.add(new pb.Field("skip", 1, "bytes", "optional"))
.add(new pb.Field("innerData", 2, "bytes", "optional"))
export const MsgHead = new pb.Type("MsgHead")
.add(BodyInner)
.add(NoifyData)
.add(new pb.Field("bodyInner", 2, "BodyInner", "optional"))
.add(new pb.Field("noifyData", 3, "NoifyData", "optional"));
export const Message = new pb.Type("Message")
.add(MsgHead)
.add(new pb.Field("msgHead", 1, "MsgHead"))
export const SubDetail = new pb.Type("SubDetail")
.add(new pb.Field("msgSeq", 1, "uint32"))
.add(new pb.Field("msgTime", 2, "uint32"))
.add(new pb.Field("senderUid", 6, "string"))
export const RecallDetails = new pb.Type("RecallDetails")
.add(SubDetail)
.add(new pb.Field("operatorUid", 1, "string"))
.add(new pb.Field("subDetail", 3, "SubDetail"))
export const RecallGroup = new pb.Type("RecallGroup")
.add(RecallDetails)
.add(new pb.Field("type", 1, "int32"))
.add(new pb.Field("peerUid", 4, "uint32"))
.add(new pb.Field("recallDetails", 11, "RecallDetails"))
.add(new pb.Field("grayTipsSeq", 37, "uint32"))

View File

@@ -240,7 +240,12 @@ export interface NodeIKernelGroupService {
getGroupRecommendContactArkJson(groupCode: string): unknown;
getJoinGroupLink(groupCode: string): unknown;
getJoinGroupLink(param: {
groupCode: string,
srcId: number,//73
needShortUrl: boolean,//true
additionalParam: string//''
}): Promise<GeneralCallResult & { url?: string }>;
modifyGroupExtInfo(groupCode: string, arg: unknown): void;

BIN
src/native/external/MoeHoo.win32.node vendored Normal file

Binary file not shown.

23
src/native/index.ts Normal file
View File

@@ -0,0 +1,23 @@
import { constants } from "node:os";
import path from "path";
import { dlopen } from "process";
export class Native {
platform: string;
supportedPlatforms = ['win32'];
MoeHooExport: any = { exports: {} };
recallHookEnabled: boolean = false;
constructor(nodePath: string, platform: string = process.platform) {
this.platform = platform;
if (!this.supportedPlatforms.includes(this.platform)) {
throw new Error(`Platform ${this.platform} is not supported`);
}
dlopen(this.MoeHooExport, path.join(nodePath, './native/MoeHoo.win32.node'), constants.dlopen.RTLD_LAZY);
}
isSetReCallEnabled(): boolean {
return this.recallHookEnabled;
}
registerRecallCallback(callback: (hex: string) => any): void {
this.recallHookEnabled = true;
return this.MoeHooExport.exports.registMsgPush(callback);
}
}

View File

@@ -3,6 +3,7 @@ import BaseAction from '../BaseAction';
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import { MessageUnique } from '@/common/message-unique';
import { RawMessage } from '@/core';
export type ReturnDataType = OB11Message
@@ -32,13 +33,17 @@ class GetMsg extends BaseAction<Payload, OB11Message> {
throw new Error('消息不存在');
}
const peer = { guildId: '', peerUid: msgIdWithPeer?.Peer.peerUid, chatType: msgIdWithPeer.Peer.chatType };
const msg = await this.core.apis.MsgApi.getMsgsByMsgId(
peer,
[msgIdWithPeer?.MsgId || payload.message_id.toString()]);
const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg.msgList[0]);
let orimsg = this.obContext.recallMsgCache.get(msgIdWithPeer.MsgId);
let msg: RawMessage;
if (orimsg) {
msg = orimsg;
} else {
msg = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgIdWithPeer?.MsgId || payload.message_id.toString()])).msgList[0];
}
const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg);
if (!retMsg) throw Error('消息为空');
try {
retMsg.message_id = MessageUnique.createUniqueMsgId(peer, msg.msgList[0].msgId)!;
retMsg.message_id = MessageUnique.createUniqueMsgId(peer, msg.msgId)!;
retMsg.message_seq = retMsg.message_id;
retMsg.real_id = retMsg.message_id;
} catch (e) {

View File

@@ -15,14 +15,14 @@ export class OneBotFriendApi {
//使用前预先判断 busiId 1061
async parsePrivatePokeEvent(grayTipElement: GrayTipElement) {
const json = JSON.parse(grayTipElement.jsonGrayTipElement.jsonStr);
let pokedetail: any[] = json.items;
let pokedetail: Array<{ uid: string }> = json.items;
//筛选item带有uid的元素
pokedetail = pokedetail.filter(item => item.uid);
if (pokedetail.length == 2) {
return new OB11FriendPokeEvent(
this.core,
parseInt((await this.core.apis.UserApi.getUinByUidV2(pokedetail[0].uid))!),
parseInt((await this.core.apis.UserApi.getUinByUidV2(pokedetail[1].uid))!),
parseInt((await this.core.apis.UserApi.getUinByUidV2(pokedetail[0].uid))),
parseInt((await this.core.apis.UserApi.getUinByUidV2(pokedetail[1].uid))),
pokedetail,
);
}

View File

@@ -96,7 +96,6 @@ export class OneBotGroupApi {
if (GroupIncreaseEvent) return GroupIncreaseEvent;
}
//代码歧义 GrayTipElementSubType.MEMBER_NEW_TITLE
else if (element.grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
const json = JSON.parse(element.grayTipElement.jsonGrayTipElement.jsonStr);
if (element.grayTipElement.jsonGrayTipElement.busiId == 1061) {
@@ -139,7 +138,6 @@ export class OneBotGroupApi {
// 获取MsgSeq+Peer可获取具体消息
}
if (element.grayTipElement.jsonGrayTipElement.busiId == 2407) {
//下面得改 上面也是错的grayTipElement.subElementType == GrayTipElementSubType.MEMBER_NEW_TITLE
const type = json.items[json.items.length - 1]?.txt;
switch (type) {
case "头衔": {
@@ -207,7 +205,6 @@ export class OneBotGroupApi {
while ((match = regex.exec(xmlElement.content)) !== null) {
matches.push(match[1]);
}
// log("新人进群匹配到的QQ号", matches)
if (matches.length === 2) {
const [inviter, invitee] = matches;
return new OB11GroupIncreaseEvent(

View File

@@ -212,7 +212,7 @@ export class OneBotMsgApi {
},
});
if (records.peerUin === '284840486') {
if (records.peerUin === '284840486' || records.peerUin === '1094950020') {
return createReplyData(records.msgId);
}
const replyMsg = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, element.replyMsgTime, [element.senderUidStr]))
@@ -234,19 +234,29 @@ export class OneBotMsgApi {
//读取视频链接并兜底
let videoUrlWrappers: Awaited<ReturnType<typeof this.core.apis.FileApi.getVideoUrl>> | undefined;
if (msg.peerUin === '284840486') {
//TODO: 合并消息内部 应该进行特殊处理 可能需要重写peer 待测试与研究 Mlikiowa Tagged
}
try {
videoUrlWrappers = await this.core.apis.FileApi.getVideoUrl({
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '0',
}, msg.msgId, elementWrapper.elementId);
} catch (error) {
this.core.context.logger.logWarn('获取视频 URL 失败');
if (msg.peerUin === '284840486' || msg.peerUin === '1094950020') {
try {
videoUrlWrappers = await this.core.apis.FileApi.getVideoUrl({
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '0',
}, msg.parentMsgIdList[0] ?? msg.msgId, elementWrapper.elementId);
} catch (error) {
this.core.context.logger.logWarn('合并获取视频 URL 失败');
}
} else {
try {
videoUrlWrappers = await this.core.apis.FileApi.getVideoUrl({
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '0',
}, msg.msgId, elementWrapper.elementId);
} catch (error) {
this.core.context.logger.logWarn('获取视频 URL 失败');
}
}
//读取在线URL
let videoDownUrl: string | undefined;
@@ -447,7 +457,6 @@ export class OneBotMsgApi {
},
};
},
[OB11MessageDataType.mface]: async ({
data: {
emoji_package_id, emoji_id, key, summary,
@@ -510,13 +519,12 @@ export class OneBotMsgApi {
faceElement: {
faceIndex: FaceIndex.dice,
faceType: FaceType.dice,
'faceText': '[骰子]',
'packId': '1',
'stickerId': '33',
'sourceType': 1,
'stickerType': 2,
// resultId: resultId.toString(),
'surpriseId': '',
faceText: '[骰子]',
packId: '1',
stickerId: '33',
sourceType: 1,
stickerType: 2,
surpriseId: '',
// "randomType": 1,
},
}),
@@ -525,15 +533,14 @@ export class OneBotMsgApi {
elementType: ElementType.FACE,
elementId: '',
faceElement: {
'faceIndex': FaceIndex.RPS,
'faceText': '[包剪锤]',
'faceType': 3,
'packId': '1',
'stickerId': '34',
'sourceType': 1,
'stickerType': 2,
// 'resultId': resultId.toString(),
'surpriseId': '',
faceIndex: FaceIndex.RPS,
faceText: '[包剪锤]',
faceType: 3,
packId: '1',
stickerId: '34',
sourceType: 1,
stickerType: 2,
surpriseId: '',
// "randomType": 1,
},
}),

View File

@@ -10,6 +10,7 @@ import {
NodeIKernelBuddyListener,
NodeIKernelGroupListener,
NodeIKernelMsgListener,
Peer,
RawMessage,
SendStatusType,
} from '@/core';
@@ -43,8 +44,9 @@ import { OB11FriendRecallNoticeEvent } from '@/onebot/event/notice/OB11FriendRec
import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecallNoticeEvent';
import { LRUCache } from '@/common/lru-cache';
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
import { OB11ProfileLikeEvent } from './event/notice/OB11ProfileLikeEvent';
import { profileLikeTip, ProfileLikeTipType, SysMessage, SysMessageType } from '@/core/proto/ProfileLike';
import { Native } from '@/native';
import { Message, RecallGroup } from '@/core/proto/Message';
//OneBot实现类
export class NapCatOneBot11Adapter {
readonly core: NapCatCore;
@@ -54,8 +56,9 @@ export class NapCatOneBot11Adapter {
apis: StableOneBotApiWrapper;
networkManager: OB11NetworkManager;
actions: ActionMap;
nativeCore: Native | undefined;
private bootTime = Date.now() / 1000;
recallMsgCache = new LRUCache<string, RawMessage>(100);
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
this.core = core;
@@ -70,10 +73,54 @@ export class NapCatOneBot11Adapter {
};
this.actions = createActionMap(this, core);
this.networkManager = new OB11NetworkManager();
this.registerNative(core, context).then().catch();
this.InitOneBot()
.catch(e => this.context.logger.logError.bind(this.context.logger)('初始化OneBot失败', e));
}
}
async registerNative(core: NapCatCore, context: InstanceContext) {
this.nativeCore = new Native(context.pathWrapper.binaryPath);
this.nativeCore.registerRecallCallback(async (hex: string) => {
try {
let data = Message.decode(Buffer.from(hex, 'hex')) as any;
//data.MsgHead.BodyInner.MsgType SubType
let bodyInner = data.msgHead?.bodyInner;
//context.logger.log("[appNative] Parse MsgType:" + bodyInner.msgType + " / SubType:" + bodyInner.subType);
if (bodyInner && bodyInner.msgType == 732 && bodyInner.subType == 17) {
let RecallData = Buffer.from(data.msgHead.noifyData.innerData);
//跳过 4字节 群号 + 不知道的1字节 +2字节 长度
let uid = RecallData.readUint32BE();
const buffer = Buffer.from(RecallData.toString('hex').slice(14), 'hex');
let seq: number = (RecallGroup.decode(buffer) as any).recallDetails.subDetail.msgSeq;
let peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: uid.toString() };
context.logger.log("[Native] 群消息撤回 Peer: " + uid.toString() + " / MsgSeq:" + seq);
let msgs = await core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, seq.toString());
this.recallMsgCache.put(msgs.msgList[0].msgId, msgs.msgList[0]);
// let ob11 = await this.apis.MsgApi.parseMessage(msgs.msgList[0], 'array')
// .catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
// if (ob11) {
// const { sendElements, deleteAfterSentFiles } = await this.apis.MsgApi.createSendElements(ob11.message as OB11MessageData[], peer);
// this.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, deleteAfterSentFiles);
// }
// 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);
}
});
}
async InitOneBot() {
const selfInfo = this.core.selfInfo;
const ob11Config = this.configLoader.configData;
@@ -523,7 +570,6 @@ export class NapCatOneBot11Adapter {
}
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructPrivateEvent error: ', e));
}
private async emitRecallMsg(msgList: RawMessage[], cache: LRUCache<string, boolean>) {
for (const message of msgList) {
// log("message update", message.sendStatus, message.msgId, message.msgSeq)
@@ -555,7 +601,7 @@ export class NapCatOneBot11Adapter {
parseInt(message.peerUin),
parseInt(message.senderUin),
parseInt(operatorId),
oriMessageId,
oriMessageId
);
this.networkManager.emitEvent(groupRecallEvent)
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理群消息撤回失败', e));

View File

@@ -54,7 +54,6 @@ export async function NCoreInitShell() {
const loginService = wrapper.NodeIKernelLoginService.get();
const session = wrapper.NodeIQQNTWrapperSession.create();
// from get dataPath
const [dataPath, dataPathGlobal] = (() => {
if (os.platform() === 'darwin') {
@@ -72,15 +71,15 @@ export async function NCoreInitShell() {
})();
let systemPlatform = PlatformType.KWINDOWS;
switch (os.platform()) {
case 'win32':
systemPlatform = PlatformType.KWINDOWS;
break;
case 'darwin':
systemPlatform = PlatformType.KMAC;
break;
case 'linux':
systemPlatform = PlatformType.KLINUX;
break;
case 'win32':
systemPlatform = PlatformType.KWINDOWS;
break;
case 'darwin':
systemPlatform = PlatformType.KMAC;
break;
case 'linux':
systemPlatform = PlatformType.KLINUX;
break;
}
if (!basicInfoWrapper.QQVersionAppid || !basicInfoWrapper.QQVersionQua) throw new Error('QQVersionAppid or QQVersionQua is not defined');
// from initConfig
@@ -119,7 +118,7 @@ export async function NCoreInitShell() {
quickLoginUin = '';
}
}
let dataTimestape = new Date().getTime().toString();
const dataTimestape = new Date().getTime().toString();
o3Service.reportAmgomWeather('login', 'a1', [dataTimestape, '0', '0']);
const selfInfo = await new Promise<SelfInfo>((resolve) => {
const loginListener = new NodeIKernelLoginListener();
@@ -234,13 +233,13 @@ export async function NCoreInitShell() {
logger.log(`可用于快速登录的 QQ\n${historyLoginList
.map((u, index) => `${index + 1}. ${u.uin} ${u.nickName}`)
.join('\n')
}`);
}`);
}
loginService.getQRCodePicture();
}
});
// BEFORE LOGGING IN
let amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
const amgomDataPiece = 'eb1fd6ac257461580dc7438eb099f23aae04ca679f4d88f53072dc56e3bb1129';
o3Service.setAmgomDataPiece(basicInfoWrapper.QQVersionAppid, new Uint8Array(Buffer.from(amgomDataPiece, 'hex')));
// AFTER LOGGING IN
//99b15bdb4c984fc69d5aa1feb9aa16xx --> 99b15bdb-4c98-4fc6-9d5a-a1feb9aa16xx

View File

@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
undefined,
SettingButton('V2.6.15', 'napcat-update-button', 'secondary'),
SettingButton('V2.6.16', 'napcat-update-button', 'secondary'),
),
]),
SettingList([

View File

@@ -164,7 +164,7 @@ async function onSettingWindowCreated(view) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
void 0,
SettingButton("V2.6.15", "napcat-update-button", "secondary")
SettingButton("V2.6.16", "napcat-update-button", "secondary")
)
]),
SettingList([

View File

@@ -41,6 +41,7 @@ const FrameworkBaseConfigPlugin: PluginOption[] = [
const ShellBaseConfigPlugin: PluginOption[] = [
cp({
targets: [
{ src: './src/native/external', dest: 'dist/native', flatten: false },
{ src: './static/', dest: 'dist/static/', flatten: false },
{ src: './src/core/external/napcat.json', dest: 'dist/config/' },
{ src: './src/onebot/config/onebot11.json', dest: 'dist/config/' },