Compare commits

..

7 Commits

Author SHA1 Message Date
手瓜一十雪
3bb12e3f45 fix: #572 2024-11-28 10:56:57 +08:00
手瓜一十雪
1dc2f7e5a2 style: lint 2024-11-28 10:46:14 +08:00
手瓜一十雪
2531b08538 refactor: 提高解析兼容 2024-11-28 10:41:51 +08:00
手瓜一十雪
9fcfb5493c fix: #571 2024-11-28 10:27:04 +08:00
Mlikiowa
4576354c51 release: v4.2.3 2024-11-28 01:54:43 +00:00
手瓜一十雪
1dcf2ef0c6 fix: error handle 2024-11-28 09:53:50 +08:00
Mlikiowa
3642c65e8c release: v4.2.2 2024-11-27 12:39:03 +00:00
11 changed files with 81 additions and 70 deletions

View File

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

View File

@@ -2,7 +2,7 @@
"name": "napcat",
"private": true,
"type": "module",
"version": "4.2.1",
"version": "4.2.3",
"scripts": {
"build:framework": "npm run build:webui && vite build --mode framework || exit 1",
"build:shell": "npm run build:webui && vite build --mode shell || exit 1",

View File

@@ -190,16 +190,27 @@ export async function checkUriType(Uri: string) {
}, Uri);
if (LocalFileRet) return LocalFileRet;
const OtherFileRet = await solveProblem((uri: string) => {
//再判断是否是Http
if (uri.startsWith('http://') || uri.startsWith('https://')) {
// 再判断是否是Http
if (uri.startsWith('http:') || uri.startsWith('https:')) {
return { Uri: uri, Type: FileUriType.Remote };
}
//再判断是否是Base64
if (uri.startsWith('base64://')) {
// 再判断是否是Base64
if (uri.startsWith('base64:')) {
return { Uri: uri, Type: FileUriType.Base64 };
}
if (uri.startsWith('file://')) {
let filePath: string = uri.slice(7);
// 默认file://
if (uri.startsWith('file:')) {
// 兼容file:///
// file:///C:/1.jpg
if (uri.startsWith('file:///') && process.platform === 'win32') {
const filePath: string = uri.slice(8);
return { Uri: filePath, Type: FileUriType.Local };
}
// 处理默认规范
// file://C:\1.jpg
// file:///test/1.jpg
const filePath: string = uri.slice(7);
return { Uri: filePath, Type: FileUriType.Local };
}
if (uri.startsWith('data:')) {
@@ -235,7 +246,7 @@ export async function uri2local(dir: string, uri: string, filename: string | und
fs.copyFileSync(HandledUri, filePath);
return { success: true, errMsg: '', fileName: filename, ext: fileExt, path: filePath };
}
//接下来都要有文件名
if (UriType == FileUriType.Remote) {
const pathInfo = path.parse(decodeURIComponent(new URL(HandledUri).pathname));

View File

@@ -1 +1 @@
export const napCatVersion = '4.2.1';
export const napCatVersion = '4.2.3';

View File

@@ -41,7 +41,7 @@ export class NTQQFileApi {
this.rkeyManager = new RkeyManager([
'https://rkey.napneko.icu/rkeys'
],
this.context.logger
this.context.logger
);
}
@@ -307,18 +307,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

@@ -62,7 +62,7 @@ export const GroupChange = {
operatorUid: ProtoField(5, ScalarType.STRING, true),
increaseType: ProtoField(6, ScalarType.UINT32),
field7: ProtoField(7, ScalarType.BYTES, true),
}
};
export const PushMsgBody = {
responseHead: ProtoField(1, () => ResponseHead),

View File

@@ -315,7 +315,7 @@ export class OneBotGroupApi {
} else if (grayTipElement.jsonGrayTipElement.busiId == JsonGrayBusiId.AIO_GROUP_ESSENCE_MSG_TIP) {
return await this.parseEssenceMsg(msg, grayTipElement.jsonGrayTipElement.jsonStr);
} else {
return await this.parseOtherJsonEvent(msg, grayTipElement.jsonGrayTipElement.jsonStr, this.core.context)
return await this.parseOtherJsonEvent(msg, grayTipElement.jsonGrayTipElement.jsonStr, this.core.context);
}
}
return undefined;

View File

@@ -673,7 +673,7 @@ export class OneBotMsgApi {
if (grayTipElement.subElementType == NTGrayTipElementSubTypeV2.GRAYTIP_ELEMENT_SUBTYPE_JSON) {
if (grayTipElement.jsonGrayTipElement.busiId == 1061) {
const PokeEvent = await this.obContext.apis.FriendApi.parsePrivatePokeEvent(grayTipElement);
if (PokeEvent) { return PokeEvent };
if (PokeEvent) { return PokeEvent; };
} else if (grayTipElement.jsonGrayTipElement.busiId == 19324 && msg.peerUid !== '') {
return new OB11FriendAddNoticeEvent(this.core, Number(await this.core.apis.UserApi.getUinByUidV2(msg.peerUid)));
}
@@ -841,14 +841,14 @@ export class OneBotMsgApi {
}
private async convertArrayToStringMessage(originMsg: OB11Message): Promise<OB11Message> {
let msg = structuredClone(originMsg);
const msg = structuredClone(originMsg);
msg.message_format = 'string';
msg.message = msg.raw_message;
return msg;
}
async importArrayTostringMsg(originMsg: OB11Message) {
let msg = structuredClone(originMsg);
const msg = structuredClone(originMsg);
msg.message_format = 'string';
msg.message = msg.raw_message;
return msg;
@@ -924,7 +924,7 @@ export class OneBotMsgApi {
fsPromise.unlink(file).then().catch(e => this.core.context.logger.logError.bind(this.core.context.logger)('发送消息删除文件失败', e));
}
} catch (error) {
this.core.context.logger.logError.bind(this.core.context.logger)('发送消息删除文件失败', (error as Error).message)
this.core.context.logger.logError.bind(this.core.context.logger)('发送消息删除文件失败', (error as Error).message);
}
});
}, 60000);
@@ -959,29 +959,20 @@ export class OneBotMsgApi {
}
groupChangDecreseType2String(type: number): GroupDecreaseSubType {
switch (type) {
case 130:
return 'kick';
case 131:
return 'leave';
case 3:
return 'kick_me';
default:
return 'kick';
case 130:
return 'kick';
case 131:
return 'leave';
case 3:
return 'kick_me';
default:
return 'kick';
}
}
async parseSysMessage(msg: number[]) {
// Todo Refactor
// const sysMsg = decodeSysMessage(Uint8Array.from(msg));
// if (sysMsg.msgSpec.length === 0) {
// return;
// }
// const { msgType, subType, subSubType } = sysMsg.msgSpec[0];
// if (msgType === 528 && subType === 39 && subSubType === 39) {
// if (!sysMsg.bodyWrapper) return;
// return await this.obContext.apis.UserApi.parseLikeEvent(sysMsg.bodyWrapper.wrappedBody);
// }
let SysMessage = new NapProtoMsg(PushMsgBody).decode(Uint8Array.from(msg));
const SysMessage = new NapProtoMsg(PushMsgBody).decode(Uint8Array.from(msg));
if (SysMessage.contentHead.type == 33 && SysMessage.body?.msgContent) {
const groupChange = new NapProtoMsg(GroupChange).decode(SysMessage.body.msgContent);
console.log(JSON.stringify(groupChange));
@@ -994,7 +985,6 @@ export class OneBotMsgApi {
);
} else if (SysMessage.contentHead.type == 34 && SysMessage.body?.msgContent) {
const groupChange = new NapProtoMsg(GroupChange).decode(SysMessage.body.msgContent);
// console.log(JSON.stringify(groupChange),JSON.stringify(SysMessage));
return new OB11GroupDecreaseEvent(
this.core,
groupChange.groupUin,
@@ -1002,7 +992,10 @@ export class OneBotMsgApi {
groupChange.operatorUid ? +await this.core.apis.UserApi.getUinByUidV2(groupChange.operatorUid) : 0,
this.groupChangDecreseType2String(groupChange.decreaseType),
);
} else if (SysMessage.contentHead.type == 528 && SysMessage.contentHead.subType == 39 && SysMessage.body?.msgContent) {
return await this.obContext.apis.UserApi.parseLikeEvent(SysMessage.body?.msgContent);
}
/*
if (msgType === 732 && subType === 16 && subSubType === 16) {
const greyTip = GreyTipWrapper.fromBinary(Uint8Array.from(sysMsg.bodyWrapper!.wrappedBody.slice(7)));

View File

@@ -13,7 +13,7 @@ export class OneBotUserApi {
}
async parseLikeEvent(wrappedBody: Uint8Array): Promise<OB11ProfileLikeEvent | undefined> {
const likeTip = decodeProfileLikeTip(Uint8Array.from(wrappedBody));
const likeTip = decodeProfileLikeTip(wrappedBody);
if (likeTip?.msgType !== 0 || likeTip?.subType !== 203) return;
this.core.context.logger.logDebug("收到点赞通知消息");
const likeMsg = likeTip.content.msg;

View File

@@ -213,7 +213,7 @@ export class NapCatOneBot11Adapter {
if (networkChange === OB11NetworkReloadType.NetWorkClose) {
await this.networkManager.closeSomeAdaterWhenOpen([existingAdapter]);
}
} else if(adapterConfig.enable) {
} else if (adapterConfig.enable) {
const newAdapter = new adapterClass(adapterConfig.name, adapterConfig, this.core, this.actions);
await this.networkManager.registerAdapterAndOpen(newAdapter);
}
@@ -266,23 +266,30 @@ export class NapCatOneBot11Adapter {
};
msgListener.onAddSendMsg = async (msg) => {
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) {
await this.core.eventWrapper.registerListen('NodeIKernelMsgListener/onMsgInfoListUpdate', (msgList: RawMessage[]) => {
const report = msgList.find((e) =>
e.senderUin == this.core.selfInfo.uin && e.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && e.msgId === msg.msgId
);
return !!report;
}, 1, 300);
msg.id = MessageUnique.createUniqueMsgId(
{
chatType: msg.chatType,
peerUid: msg.peerUid,
guildId: '',
},
msg.msgId
);
//此时上报的seq不是对的 不过对onebot业务无影响
this.emitMsg(msg);
try {
if (msg.sendStatus == SendStatusType.KSEND_STATUS_SENDING) {
const [updatemsgs] = await this.core.eventWrapper.registerListen('NodeIKernelMsgListener/onMsgInfoListUpdate', (msgList: RawMessage[]) => {
const report = msgList.find((e) =>
e.senderUin == this.core.selfInfo.uin && e.sendStatus !== SendStatusType.KSEND_STATUS_SENDING && e.msgId === msg.msgId
);
return !!report;
}, 1, 10 * 60 * 1000);
// 10分钟 超时
const updatemsg = updatemsgs.find((e) => e.msgId === msg.msgId);
if (updatemsg?.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS || updatemsg?.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS_NOSEQ) {
updatemsg.id = MessageUnique.createUniqueMsgId(
{
chatType: updatemsg.chatType,
peerUid: updatemsg.peerUid,
guildId: '',
},
updatemsg.msgId
);
this.emitMsg(updatemsg);
}
}
} catch (error) {
this.context.logger.logError('处理发送消息失败', error);
}
};
msgListener.onMsgRecall = async (chatType: ChatType, uid: string, msgSeq: string) => {
@@ -291,10 +298,10 @@ export class NapCatOneBot11Adapter {
peerUid: uid,
guildId: ''
};
let msg = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, msgSeq)).msgList.find(e => e.msgType == NTMsgType.KMSGTYPEGRAYTIPS);
let element = msg?.elements[0];
const msg = (await this.core.apis.MsgApi.queryMsgsWithFilterExWithSeq(peer, msgSeq)).msgList.find(e => e.msgType == NTMsgType.KMSGTYPEGRAYTIPS);
const element = msg?.elements[0];
if (msg && element) {
let recallEvent = await this.emitRecallMsg(msg, element);
const recallEvent = await this.emitRecallMsg(msg, element);
try {
if (recallEvent) {
await this.networkManager.emitEvent(recallEvent);
@@ -303,7 +310,7 @@ export class NapCatOneBot11Adapter {
this.context.logger.logError('处理消息撤回失败', e);
}
}
}
};
msgListener.onKickedOffLine = async (kick) => {
const event = new BotOfflineEvent(this.core, kick.tipsTitle, kick.tipsDesc);
this.networkManager
@@ -657,7 +664,7 @@ export class NapCatOneBot11Adapter {
private async emitRecallMsg(message: RawMessage, element: MessageElement) {
const peer: Peer = { chatType: message.chatType, peerUid: message.peerUid, guildId: '' };
let oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
const oriMessageId = MessageUnique.getShortIdByMsgId(message.msgId) ?? MessageUnique.createUniqueMsgId(peer, message.msgId);
if (message.chatType == ChatType.KCHATTYPEC2C) {
return await this.emitFriendRecallMsg(message, oriMessageId, element);
} else if (message.chatType == ChatType.KCHATTYPEGROUP) {
@@ -677,7 +684,7 @@ export class NapCatOneBot11Adapter {
private async emitGroupRecallMsg(message: RawMessage, oriMessageId: number, element: MessageElement) {
const operatorUid = element.grayTipElement?.revokeElement.operatorUid;
if (!operatorUid) return undefined;
let operatorId = message.senderUin ?? await this.core.apis.UserApi.getUinByUidV2(operatorUid);
const operatorId = message.senderUin ?? await this.core.apis.UserApi.getUinByUidV2(operatorUid);
return new OB11GroupRecallNoticeEvent(
this.core,
+message.peerUin,

View File

@@ -102,7 +102,7 @@ export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter {
if (req.path === '' || req.path === '/') {
const hello = OB11Response.ok({});
hello.message = 'NapCat4 Ss Running';
return res.json(hello)
return res.json(hello);
}
const actionName = req.path.split('/')[1];
const action = this.actions.get(actionName);