mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c3dc53eaaf | ||
![]() |
ffdc34cfe2 | ||
![]() |
4825a0e341 | ||
![]() |
95a00d7f35 | ||
![]() |
d885bab426 | ||
![]() |
e2a6a0bc02 | ||
![]() |
ff7d8609ce | ||
![]() |
7507b90e03 | ||
![]() |
2b226a4b27 | ||
![]() |
8b0232c4fe | ||
![]() |
0728ee9ad6 | ||
![]() |
8c6f04d0bc | ||
![]() |
c67fad789e |
@@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "3.1.10",
|
"version": "3.3.12",
|
||||||
"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.10",
|
"version": "3.3.12",
|
||||||
"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",
|
||||||
|
@@ -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.10';
|
export const napCatVersion = '3.3.12';
|
||||||
|
@@ -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,
|
||||||
|
@@ -232,7 +232,8 @@ export interface NodeIKernelGroupService {
|
|||||||
|
|
||||||
getGroupStatisticInfo(groupCode: string): unknown;
|
getGroupStatisticInfo(groupCode: string): unknown;
|
||||||
|
|
||||||
getGroupRemainAtTimes(groupCode: string): Promise<GeneralCallResult & {
|
getGroupRemainAtTimes(groupCode: string): Promise<Omit<GeneralCallResult, 'result'> & {
|
||||||
|
errCode: number,
|
||||||
atInfo: {
|
atInfo: {
|
||||||
canAtAll: boolean
|
canAtAll: boolean
|
||||||
RemainAtAllCountForUin: number
|
RemainAtAllCountForUin: number
|
||||||
|
@@ -17,9 +17,6 @@ export class GoCQHTTPGetGroupAtAllRemain extends BaseAction<Payload, any> {
|
|||||||
|
|
||||||
async _handle(payload: Payload) {
|
async _handle(payload: Payload) {
|
||||||
const ret = await this.core.apis.GroupApi.getGroupRemainAtTimes(payload.group_id.toString());
|
const ret = await this.core.apis.GroupApi.getGroupRemainAtTimes(payload.group_id.toString());
|
||||||
if (!ret.atInfo || ret.result !== 0) {
|
|
||||||
throw new Error('atInfo not found');
|
|
||||||
}
|
|
||||||
const data = {
|
const data = {
|
||||||
can_at_all: ret.atInfo.canAtAll,
|
can_at_all: ret.atInfo.canAtAll,
|
||||||
remain_at_all_count_for_group: ret.atInfo.RemainAtAllCountForGroup,
|
remain_at_all_count_for_group: ret.atInfo.RemainAtAllCountForGroup,
|
||||||
|
@@ -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;
|
||||||
@@ -190,9 +191,9 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
time: Number(node.data.time) || Date.now(),
|
time: Number(node.data.time) || Date.now(),
|
||||||
msg: sendElements,
|
msg: sendElements,
|
||||||
};
|
};
|
||||||
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 开始转换 ${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[SendRaw] 转换为 ${JSON.stringify(transformedMsg)}`);
|
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
|
||||||
packetMsg.push(transformedMsg!);
|
packetMsg.push(transformedMsg!);
|
||||||
} else if (node.data.id) {
|
} else if (node.data.id) {
|
||||||
const id = node.data.id;
|
const id = node.data.id;
|
||||||
@@ -202,13 +203,13 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(nodeMsg.Peer, [nodeMsg.MsgId])).msgList[0];
|
const msg = (await this.core.apis.MsgApi.getMsgsByMsgId(nodeMsg.Peer, [nodeMsg.MsgId])).msgList[0];
|
||||||
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 开始转换 ${JSON.stringify(msg)}`);
|
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 开始转换 ${stringifyWithBigInt(msg)}`);
|
||||||
await this.core.apis.FileApi.downloadRawMsgMedia([msg]);
|
await this.core.apis.FileApi.downloadRawMsgMedia([msg]);
|
||||||
const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgToPacketMsg(msg, msgPeer);
|
const transformedMsg = this.core.apis.PacketApi.packetSession?.packer.packetConverter.rawMsgToPacketMsg(msg, msgPeer);
|
||||||
logger.logDebug(`handleForwardedNodesPacket[PureRaw] 转换为 ${JSON.stringify(transformedMsg)}`);
|
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) {
|
if (packetMsg.length === 0) {
|
||||||
|
@@ -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
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
@@ -626,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() {
|
||||||
|
@@ -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.10', '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.10", "napcat-update-button", "secondary")
|
SettingButton("V3.3.12", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
Reference in New Issue
Block a user