Compare commits

...

19 Commits

Author SHA1 Message Date
手瓜一十雪
0e69e9e839 fix: checkVersion 2024-10-27 22:32:52 +08:00
手瓜一十雪
b83229b5da feat: 自动化版本发布控制 2024-10-27 22:30:01 +08:00
手瓜一十雪
6f053f5f7d feat: 我补药要手动release啦! 2024-10-27 22:20:11 +08:00
手瓜一十雪
c3dc53eaaf release: v3.3.12 2024-10-27 22:14:17 +08:00
手瓜一十雪
ffdc34cfe2 Merge pull request #470 from pohgxz/main
修复<get_group_at_all_remain>接口总是返回<Error: atInfo not found>
2024-10-27 22:10:55 +08:00
手瓜一十雪
4825a0e341 fix: type Error 2024-10-27 22:07:11 +08:00
Nepenthe
95a00d7f35 修复<get_group_at_all_remain>接口总是返回<Error: atInfo not found> 2024-10-27 22:04:48 +08:00
手瓜一十雪
d885bab426 feat: 类型修复 2024-10-27 22:03:22 +08:00
手瓜一十雪
e2a6a0bc02 release: v3.2.12 2024-10-27 20:56:27 +08:00
手瓜一十雪
ff7d8609ce fix: #452 修复seq搜索的老问题 可能修好了 2024-10-27 20:52:09 +08:00
手瓜一十雪
7507b90e03 fix: #458 2024-10-27 20:38:02 +08:00
手瓜一十雪
2b226a4b27 release: v3.1.11 2024-10-27 19:29:42 +08:00
手瓜一十雪
8b0232c4fe fix: error 2024-10-27 11:17:01 +08:00
手瓜一十雪
0728ee9ad6 Merge branch 'main' of https://github.com/NapNeko/NapCatQQ 2024-10-27 11:09:00 +08:00
手瓜一十雪
8c6f04d0bc feat: #469 回收连接(未测试) 2024-10-27 11:08:48 +08:00
pk5ls20
c67fad789e fix: compatibility bigint 2024-10-27 10:50:48 +08:00
手瓜一十雪
4072339d70 release: v3.1.10 2024-10-27 10:03:07 +08:00
手瓜一十雪
3a244f5804 style: lint 2024-10-27 10:02:42 +08:00
pk5ls20
f12cf59137 feat: enhance compatibility of upload_forward_msg with go-cqhttp 2024-10-27 09:59:38 +08:00
22 changed files with 222 additions and 49 deletions

View File

@@ -127,6 +127,10 @@ jobs:
zip -q -r NapCat.Framework.Windows.Once.zip *
cd ..
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
run: echo "VERSION=${GITHUB_REF#refs/tags/v}" >> $GITHUB_ENV
@@ -143,4 +147,8 @@ jobs:
NapCat.Framework.zip
NapCat.Shell.zip
NapCat.Framework.Windows.Once.zip
napcat.packet.arm64
napcat.packet.exe
napcat.packet.linux
napcat.packet.production.py
draft: true

BIN
external/packet/napcat.packet.arm64 vendored Normal file

Binary file not shown.

BIN
external/packet/napcat.packet.exe vendored Normal file

Binary file not shown.

BIN
external/packet/napcat.packet.linux vendored Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "3.1.9",
"version": "3.3.12",
"scripts": {
"build:framework": "vite build --mode framework",
"build:shell": "vite build --mode shell",

View File

@@ -4,16 +4,27 @@ const process = require("process");
console.log("[NapCat] [CheckVersion] 开始检测当前仓库版本...");
try {
const packageJson = require("../package.json");
const manifsetJson = require("../manifest.json");
const currentVersion = packageJson.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] manifestCurrentVersion:", manifestCurrentVersion, "manifestTargetVersion:", manifestTargetVersion);
// 验证 targetVersion 格式
if (!targetVersion || typeof targetVersion !== 'string') {
console.log("[NapCat] [CheckVersion] 目标版本格式不正确或未设置!");
return;
}
// 验证 manifestTargetVersion 格式
if (!manifestTargetVersion || typeof manifestTargetVersion !== 'string') {
console.log("[NapCat] [CheckVersion] manifest目标版本格式不正确或未设置");
return;
}
// 写入脚本文件的统一函数
const writeScriptToFile = (content) => {
@@ -21,7 +32,7 @@ try {
console.log("[NapCat] [CheckVersion] checkVersion.sh 文件已更新。");
};
if (currentVersion === targetVersion) {
if (currentVersion === targetVersion && manifestCurrentVersion === manifestTargetVersion) {
// 不需要更新版本,写入一个简单的脚本
const simpleScript = "#!/bin/bash\necho \"CheckVersion Is Done\"";
writeScriptToFile(simpleScript);
@@ -32,6 +43,9 @@ try {
git config --global user.email "bot@test.wumiao.wang"
git config --global user.name "Version"
sed -i "s/\\\"version\\\": \\\"${currentVersion}\\\"/\\\"version\\\": \\\"${targetVersion}\\\"/g" package.json
sed -i "s/\\\"version\\\": \\\"${manifestCurrentVersion}\\\"/\\\"version\\\": \\\"${targetVersion}\\\"/g" manifest.json
sed -i "s/napCatVersion = '\\${currentVersion}'/napCatVersion = '\\${targetVersion}'/g" ./src/common/version.ts
sed -i 's/SettingButton("V[0-9]\+\.[0-9]\+\.[0-9]\+", "napcat-update-button", "secondary")/SettingButton("'"${targetVersion}"'", "napcat-update-button", "secondary")/g' ./static/assets/renderer.js
git add .
git commit -m "chore:version change"
git push -u origin main`;

View File

@@ -239,3 +239,9 @@ export function calcQQLevel(level?: QQLevel) {
const { crownNum, sunNum, moonNum, starNum } = level;
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
);
}

View File

@@ -1 +1 @@
export const napCatVersion = '3.1.9';
export const napCatVersion = '3.3.12';

View File

@@ -296,18 +296,18 @@ export class NTQQFileApi {
element.elementType === ElementType.FILE
) {
switch (element.elementType) {
case ElementType.PIC:
case ElementType.PIC:
element.picElement!.sourcePath = elementResults[elementIndex];
break;
case ElementType.VIDEO:
break;
case ElementType.VIDEO:
element.videoElement!.filePath = elementResults[elementIndex];
break;
case ElementType.PTT:
break;
case ElementType.PTT:
element.pttElement!.filePath = elementResults[elementIndex];
break;
case ElementType.FILE:
break;
case ElementType.FILE:
element.fileElement!.filePath = elementResults[elementIndex];
break;
break;
}
elementIndex++;
}

View File

@@ -82,6 +82,18 @@ export class NTQQMsgApi {
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) {
return await this.context.session.getMsgService().queryMsgsWithFilterEx('0', '0', msgSeq, {
chatInfo: peer,

View File

@@ -31,8 +31,8 @@ import {
PacketMsgVideoElement,
PacketMultiMsgElement
} from "@/core/packet/msg/element";
import {PacketMsg, PacketSendMsgElement} from "@/core/packet/msg/message";
import {LogWrapper} from "@/common/log";
import { PacketMsg, PacketSendMsgElement } from "@/core/packet/msg/message";
import { LogWrapper } from "@/common/log";
const SupportedElementTypes = [
ElementType.TEXT,
@@ -118,7 +118,7 @@ export class PacketMsgConverter {
if (!this.isValidElementType(element.elementType)) return null;
return this.rawToPacketMsgConverters[element.elementType](element);
}).filter((e) => e !== null)
}
};
}
private rawToPacketMsgConverters: ElementToPacketMsgConverters = {

View File

@@ -232,7 +232,8 @@ export interface NodeIKernelGroupService {
getGroupStatisticInfo(groupCode: string): unknown;
getGroupRemainAtTimes(groupCode: string): Promise<GeneralCallResult & {
getGroupRemainAtTimes(groupCode: string): Promise<Omit<GeneralCallResult, 'result'> & {
errCode: number,
atInfo: {
canAtAll: boolean
RemainAtAllCountForUin: number

View File

@@ -16,11 +16,8 @@ export class GoCQHTTPGetGroupAtAllRemain extends BaseAction<Payload, any> {
payloadSchema = SchemaData;
async _handle(payload: Payload) {
let ret = await this.core.apis.GroupApi.getGroupRemainAtTimes(payload.group_id.toString());
if (!ret.atInfo || ret.result !== 0) {
throw new Error('atInfo not found');
}
let data = {
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

View File

@@ -18,7 +18,7 @@ export class GoCQHTTPDeleteFriend extends BaseAction<Payload, any> {
payloadSchema = SchemaData;
async _handle(payload: Payload) {
let uid = await this.core.apis.UserApi.getUidByUinV2(payload.friend_id.toString());
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.friend_id.toString());
if (!uid) {
return {
@@ -26,7 +26,7 @@ export class GoCQHTTPDeleteFriend extends BaseAction<Payload, any> {
message: '好友不存在',
};
}
let isBuddy = await this.core.apis.FriendApi.isBuddy(uid);
const isBuddy = await this.core.apis.FriendApi.isBuddy(uid);
if (!isBuddy) {
return {
valid: false,

View File

@@ -14,6 +14,7 @@ import BaseAction from '../BaseAction';
import { rawMsgWithSendMsg } from "@/core/packet/msg/converter";
import { PacketMsg } from "@/core/packet/msg/message";
import { ForwardMsgBuilder } from "@/common/forward-msg-builder";
import { stringifyWithBigInt } from "@/common/helper";
export interface ReturnDataType {
message_id: number;
@@ -172,10 +173,10 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
const OB11Data = normalize(node.type === OB11MessageDataType.node ? node.data.content : node);
let sendElements: SendMessageElement[];
if (getSpecialMsgNum({message: OB11Data}, OB11MessageDataType.node)) {
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?.toString() ?? parentMeta?.user_id ?? this.core.selfInfo.uin,
nickname: node.data.nickname ?? parentMeta?.nickname ?? "QQ用户",
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 {
@@ -184,15 +185,15 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
}
const packetMsgElements: rawMsgWithSendMsg = {
senderUin: Number(node.data.user_id ?? parentMeta?.user_id) || +this.core.selfInfo.uin,
senderName: node.data.nickname ?? parentMeta?.nickname ?? "QQ用户",
senderUin: Number((node.data.user_id || node.data.uin) ?? parentMeta?.user_id) || +this.core.selfInfo.uin,
senderName: (node.data.nickname || node.data.name) ?? parentMeta?.nickname ?? "QQ用户",
groupId: msgPeer.chatType === ChatType.KCHATTYPEGROUP ? +msgPeer.peerUid : undefined,
time: Number(node.data.time) || Date.now(),
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);
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${JSON.stringify(transformedMsg)}`);
logger.logDebug(`handleForwardedNodesPacket[SendRaw] 转换为 ${stringifyWithBigInt(transformedMsg)}`);
packetMsg.push(transformedMsg!);
} else if (node.data.id) {
const id = node.data.id;
@@ -202,13 +203,13 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
continue;
}
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]);
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!);
} else {
logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${JSON.stringify(node)}`);
logger.logDebug(`handleForwardedNodesPacket 跳过元素 ${stringifyWithBigInt(node)}`);
}
}
if (packetMsg.length === 0) {
@@ -241,7 +242,7 @@ export class SendMsg extends BaseAction<OB11PostSendMsg, ReturnDataType> {
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};
return { message: returnMsg ?? null, res_id };
}
private async handleForwardedNodes(destPeer: Peer, messageNodes: OB11MessageNode[]): Promise<{

View File

@@ -120,7 +120,7 @@ export class OneBotMsgApi {
url: await this.core.apis.FileApi.getImageUrl(element),
path: element.filePath,
file_size: element.fileSize,
file_unique: element.fileName
file_unique: element.md5HexStr ?? element.fileName,
},
};
} catch (e: any) {
@@ -141,9 +141,9 @@ export class OneBotMsgApi {
file: element.fileName,
path: element.filePath,
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_unique: element.fileName,
file_unique: element.fileMd5 ?? element.fileSha ?? element.fileName,
},
};
},
@@ -204,7 +204,7 @@ export class OneBotMsgApi {
guildId: '',
};
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;
}
@@ -218,11 +218,27 @@ export class OneBotMsgApi {
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]))
.msgList.find(msg => msg.msgRandom === records.msgRandom);
let replyMsgList = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeqV2(peer, element.replayMsgSeq, element.replyMsgTime, [element.senderUidStr])).msgList;
let replyMsg = replyMsgList.find(msg => msg.msgRandom === records.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 createReplyData(replyMsg.msgId);
@@ -285,7 +301,7 @@ export class OneBotMsgApi {
url: videoDownUrl ?? pathToFileURL(element.filePath).href,
file_id: fileCode,
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,
file_id: fileCode,
file_size: element.fileSize,
file_unique: element.fileName
file_unique: element.fileUuid
},
};
},
@@ -626,13 +642,13 @@ export class OneBotMsgApi {
[OB11MessageDataType.miniapp]: async () => undefined,
[OB11MessageDataType.contact]: async ({ data: { type = "qq", id } }, context) => {
if(type === "qq"){
if (type === "qq") {
const arkJson = await this.core.apis.UserApi.getBuddyRecommendContactArkJson(id.toString(), '');
return this.ob11ToRawConverters.json({
data: { data: arkJson.arkMsg },
type: OB11MessageDataType.json
}, context);
}else if(type === "group"){
} else if (type === "group") {
const arkJson = await this.core.apis.GroupApi.getGroupRecommendContactArkJson(id.toString());
return this.ob11ToRawConverters.json({
data: { data: arkJson.arkJson },

View File

@@ -119,11 +119,25 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter {
async close() {
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) {
clearInterval(this.heartbeatIntervalId);
this.heartbeatIntervalId = null;
}
await this.wsClientsMutex.runExclusive(async () => {
this.wsClients.forEach((wsClient) => {
wsClient.close();
});
this.wsClients = [];
this.wsClientWithEvent = [];
});
}
private registerHeartBeat() {

View File

@@ -150,7 +150,9 @@ export interface OB11MessageNode {
data: {
id?: string
user_id?: number | string // number
uin?: number | string // number, compatible with go-cqhttp
nickname: string
name?: string // compatible with go-cqhttp
content: OB11MessageMixType
source?: string,
news?: { text: string }[],

View File

@@ -30,7 +30,7 @@ async function onSettingWindowCreated(view: Element) {
SettingItem(
'<span id="napcat-update-title">Napcat</span>',
undefined,
SettingButton('V3.1.9', 'napcat-update-button', 'secondary'),
SettingButton('V3.3.12', '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("V3.1.9", "napcat-update-button", "secondary")
SettingButton("V3.3.12", "napcat-update-button", "secondary")
)
]),
SettingList([