Compare commits

...

7 Commits

Author SHA1 Message Date
pk5ls20
e7222653fa release: 3.0.6 2024-10-20 23:54:21 +08:00
pk5ls20
014f0758f5 chore: 部分回滚 https://github.com/NapNeko/NapCatQQ/commit/bb72d70b 2024-10-20 23:52:36 +08:00
pk5ls20
0e8b416f6d Merge pull request #448 from pk5ls20/feat/friend-poke
feat: add `friend_poke` OneBot11 API
2024-10-20 23:18:26 +08:00
pk5ls20
09a60a2204 feat: add friend_poke OneBot11 API 2024-10-20 23:09:38 +08:00
手瓜一十雪
b0eae307c2 release: 3.0.5 2024-10-20 22:18:57 +08:00
手瓜一十雪
f5d2b54cca fix: 兼容晚启动 2024-10-20 22:18:34 +08:00
手瓜一十雪
3eefec3899 release: v3.0.4 2024-10-20 19:52:23 +08:00
13 changed files with 70 additions and 41 deletions

View File

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

View File

@@ -2,7 +2,7 @@
"name": "napcat", "name": "napcat",
"private": true, "private": true,
"type": "module", "type": "module",
"version": "3.0.3", "version": "3.0.6",
"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",
@@ -49,4 +49,4 @@
"silk-wasm": "^3.6.1", "silk-wasm": "^3.6.1",
"ws": "^8.18.0" "ws": "^8.18.0"
} }
} }

View File

@@ -1 +1 @@
export const napCatVersion = '3.0.3'; export const napCatVersion = '3.0.6';

View File

@@ -1,18 +1,19 @@
import * as os from 'os'; import * as os from 'os';
import {ChatType, InstanceContext, NapCatCore} from '..'; import { ChatType, InstanceContext, NapCatCore } from '..';
import offset from '@/core/external/offset.json'; import offset from '@/core/external/offset.json';
import {PacketClient, RecvPacketData} from '@/core/packet/client'; import { PacketClient, RecvPacketData } from '@/core/packet/client';
import {PacketSession} from "@/core/packet/session"; import { PacketSession } from "@/core/packet/session";
import {PacketHexStr} from "@/core/packet/packer"; import { PacketHexStr } from "@/core/packet/packer";
import {NapProtoMsg} from '@/core/packet/proto/NapProto'; import { NapProtoMsg } from '@/core/packet/proto/NapProto';
import {OidbSvcTrpcTcp0X9067_202_Rsp_Body} from '@/core/packet/proto/oidb/Oidb.0x9067_202'; import { OidbSvcTrpcTcp0X9067_202_Rsp_Body } from '@/core/packet/proto/oidb/Oidb.0x9067_202';
import {OidbSvcTrpcTcpBase, OidbSvcTrpcTcpBaseRsp} from '@/core/packet/proto/oidb/OidbBase'; import { OidbSvcTrpcTcpBase, OidbSvcTrpcTcpBaseRsp } from '@/core/packet/proto/oidb/OidbBase';
import {OidbSvcTrpcTcp0XFE1_2RSP} from '@/core/packet/proto/oidb/Oidb.0XFE1_2'; import { OidbSvcTrpcTcp0XFE1_2RSP } from '@/core/packet/proto/oidb/Oidb.0XFE1_2';
import {LogWrapper} from "@/common/log"; import { LogWrapper } from "@/common/log";
import {SendLongMsgResp} from "@/core/packet/proto/message/action"; import { SendLongMsgResp } from "@/core/packet/proto/message/action";
import {PacketMsg} from "@/core/packet/msg/message"; import { PacketMsg } from "@/core/packet/msg/message";
import {OidbSvcTrpcTcp0x6D6Response} from "@/core/packet/proto/oidb/Oidb.0x6D6"; import { OidbSvcTrpcTcp0x6D6Response } from "@/core/packet/proto/oidb/Oidb.0x6D6";
import {PacketMsgPicElement} from "@/core/packet/msg/element"; import { PacketMsgPicElement } from "@/core/packet/msg/element";
import { c } from 'vite/dist/node/types.d-aGj9QkWt';
interface OffsetType { interface OffsetType {
[key: string]: { [key: string]: {
@@ -59,8 +60,12 @@ export class NTQQPacketApi {
if (!table) return false; if (!table) return false;
const url = 'ws://' + this.serverUrl + '/ws'; const url = 'ws://' + this.serverUrl + '/ws';
this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core)); this.packetSession = new PacketSession(this.core.context.logger, new PacketClient(url, this.core));
await this.packetSession.client.connect(); const cb = () => {
await this.packetSession.client.init(process.pid, table.recv, table.send); if (this.packetSession && this.packetSession.client) {
this.packetSession.client.init(process.pid, table.recv, table.send).then().catch(this.logger.logError.bind(this.logger));
}
}
await this.packetSession.client.connect(cb);
return true; return true;
} }
@@ -68,8 +73,8 @@ export class NTQQPacketApi {
return this.packetSession!.client.sendPacket(cmd, data, rsp); return this.packetSession!.client.sendPacket(cmd, data, rsp);
} }
async sendPokePacket(group: number, peer: number) { async sendPokePacket(peer: number, group?: number) {
const data = this.packetSession?.packer.packPokePacket(group, peer); const data = this.packetSession?.packer.packPokePacket(peer, group);
await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data!, false); await this.sendPacket('OidbSvcTrpcTcp.0xed3_1', data!, false);
} }
@@ -106,11 +111,11 @@ export class NTQQPacketApi {
await this.sendPacket('OidbSvcTrpcTcp.0x8fc_2', data!, true); await this.sendPacket('OidbSvcTrpcTcp.0x8fc_2', data!, true);
} }
private async uploadResources(msg: PacketMsg[], groupUin: number = 0){ private async uploadResources(msg: PacketMsg[], groupUin: number = 0) {
const reqList = [] const reqList = []
for (const m of msg){ for (const m of msg) {
for (const e of m.msg){ for (const e of m.msg) {
if (e instanceof PacketMsgPicElement){ if (e instanceof PacketMsgPicElement) {
reqList.push(this.packetSession?.highwaySession.uploadImage({ reqList.push(this.packetSession?.highwaySession.uploadImage({
chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C, chatType: groupUin ? ChatType.KCHATTYPEGROUP : ChatType.KCHATTYPEC2C,
peerUid: String(groupUin) ? String(groupUin) : this.core.selfInfo.uid peerUid: String(groupUin) ? String(groupUin) : this.core.selfInfo.uid
@@ -135,7 +140,7 @@ export class NTQQPacketApi {
const ret = await this.sendPacket('OidbSvcTrpcTcp.0x6d6_2', data!, true); const ret = await this.sendPacket('OidbSvcTrpcTcp.0x6d6_2', data!, true);
const body = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(Buffer.from(ret.hex_data, 'hex')).body; const body = new NapProtoMsg(OidbSvcTrpcTcpBaseRsp).decode(Buffer.from(ret.hex_data, 'hex')).body;
const resp = new NapProtoMsg(OidbSvcTrpcTcp0x6D6Response).decode(body); const resp = new NapProtoMsg(OidbSvcTrpcTcp0x6D6Response).decode(body);
if (resp.download.retCode !== 0){ if (resp.download.retCode !== 0) {
throw new Error(`sendGroupFileDownloadReq error: ${resp.download.clientWording}`); throw new Error(`sendGroupFileDownloadReq error: ${resp.download.clientWording}`);
} }
return `https://${resp.download.downloadDns}/ftn_handler/${Buffer.from(resp.download.downloadUrl).toString('hex')}/?fname=` return `https://${resp.download.downloadDns}/ftn_handler/${Buffer.from(resp.download.downloadUrl).toString('hex')}/?fname=`

View File

@@ -22,7 +22,7 @@ export class PacketClient {
private websocket: WebSocket | undefined; private websocket: WebSocket | undefined;
private isConnected: boolean = false; private isConnected: boolean = false;
private reconnectAttempts: number = 0; private reconnectAttempts: number = 0;
private readonly maxReconnectAttempts: number = 5;//现在暂时不可配置 private readonly maxReconnectAttempts: number = 60;//现在暂时不可配置
private readonly cb = new LRUCache<string, (json: RecvPacketData) => Promise<void>>(500); // trace_id-type callback private readonly cb = new LRUCache<string, (json: RecvPacketData) => Promise<void>>(500); // trace_id-type callback
private readonly clientUrl: string = ''; private readonly clientUrl: string = '';
readonly napCatCore: NapCatCore; readonly napCatCore: NapCatCore;
@@ -47,16 +47,17 @@ export class PacketClient {
return text; return text;
} }
connect(): Promise<void> { connect(cb: any): Promise<void> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
//this.logger.log.bind(this.logger)(`[Core] [Packet Server] Attempting to connect to ${this.clientUrl}`); //this.logger.log.bind(this.logger)(`[Core] [Packet Server] Attempting to connect to ${this.clientUrl}`);
this.websocket = new WebSocket(this.clientUrl); this.websocket = new WebSocket(this.clientUrl);
this.websocket.on('error', (err) => {}/*this.logger.logError.bind(this.logger)('[Core] [Packet Server] Error:', err.message)*/); this.websocket.on('error', (err) => { }/*this.logger.logError.bind(this.logger)('[Core] [Packet Server] Error:', err.message)*/);
this.websocket.onopen = () => { this.websocket.onopen = () => {
this.isConnected = true; this.isConnected = true;
this.reconnectAttempts = 0; this.reconnectAttempts = 0;
this.logger.log.bind(this.logger)(`[Core] [Packet Server] Connected to ${this.clientUrl}`); this.logger.log.bind(this.logger)(`[Core] [Packet Server] Connected to ${this.clientUrl}`);
cb();
resolve(); resolve();
}; };
@@ -74,17 +75,17 @@ export class PacketClient {
this.websocket.onclose = () => { this.websocket.onclose = () => {
this.isConnected = false; this.isConnected = false;
//this.logger.logWarn.bind(this.logger)(`[Core] [Packet Server] Disconnected from ${this.clientUrl}`); //this.logger.logWarn.bind(this.logger)(`[Core] [Packet Server] Disconnected from ${this.clientUrl}`);
this.attemptReconnect(); this.attemptReconnect(cb);
}; };
}); });
} }
private attemptReconnect(): void { private attemptReconnect(cb: any): void {
try { try {
if (this.reconnectAttempts < this.maxReconnectAttempts) { if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++; this.reconnectAttempts++;
setTimeout(() => { setTimeout(() => {
this.connect().catch((error) => { this.connect(cb).catch((error) => {
this.logger.logError.bind(this.logger)(`[Core] [Packet Server] Reconnecting attempt failed,${error.message}`); this.logger.logError.bind(this.logger)(`[Core] [Packet Server] Reconnecting attempt failed,${error.message}`);
}); });
}, 5000 * this.reconnectAttempts); }, 5000 * this.reconnectAttempts);

View File

@@ -47,11 +47,11 @@ export class PacketPacker {
}); });
} }
packPokePacket(group: number, peer: number): PacketHexStr { packPokePacket(peer: number, group?: number): PacketHexStr {
const oidb_0xed3 = new NapProtoMsg(OidbSvcTrpcTcp0XED3_1).encode({ const oidb_0xed3 = new NapProtoMsg(OidbSvcTrpcTcp0XED3_1).encode({
uin: peer, uin: peer,
groupUin: group, groupUin: group,
friendUin: group, friendUin: group ?? peer,
ext: 0 ext: 0
}); });
return this.toHexStr(this.packOidbPacket(0xed3, 1, oidb_0xed3)); return this.toHexStr(this.packOidbPacket(0xed3, 1, oidb_0xed3));

View File

@@ -18,6 +18,6 @@ export class GroupPoke extends GetPacketStatusDepends<Payload, any> {
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload) { async _handle(payload: Payload) {
await this.core.apis.PacketApi.sendPokePacket(+payload.group_id, +payload.user_id); await this.core.apis.PacketApi.sendPokePacket(+payload.user_id, +payload.group_id);
} }
} }

View File

@@ -91,6 +91,7 @@ import { GetGroupShutList } from './group/GetGroupShutList';
import { GetGroupMemberList } from './group/GetGroupMemberList'; import { GetGroupMemberList } from './group/GetGroupMemberList';
import { GetGroupFileUrl } from "@/onebot/action/file/GetGroupFileUrl"; import { GetGroupFileUrl } from "@/onebot/action/file/GetGroupFileUrl";
import {GetPacketStatus} from "@/onebot/action/packet/GetPacketStatus"; import {GetPacketStatus} from "@/onebot/action/packet/GetPacketStatus";
import {FriendPoke} from "@/onebot/action/user/FriendPoke";
export type ActionMap = Map<string, BaseAction<any, any>>; export type ActionMap = Map<string, BaseAction<any, any>>;
@@ -189,6 +190,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
new FetchUserProfileLike(obContext, core), new FetchUserProfileLike(obContext, core),
new GetPacketStatus(obContext, core), new GetPacketStatus(obContext, core),
new GroupPoke(obContext, core), new GroupPoke(obContext, core),
new FriendPoke(obContext, core),
new GetUserStatus(obContext, core), new GetUserStatus(obContext, core),
new GetRkey(obContext, core), new GetRkey(obContext, core),
new SetSpecialTittle(obContext, core), new SetSpecialTittle(obContext, core),

View File

@@ -17,6 +17,7 @@ export enum ActionName {
// 以下为扩展napcat扩展 // 以下为扩展napcat扩展
Unknown = 'unknown', Unknown = 'unknown',
GroupPoke = 'group_poke', GroupPoke = 'group_poke',
FriendPoke = 'friend_poke',
SharePeer = 'ArkSharePeer', SharePeer = 'ArkSharePeer',
ShareGroupEx = 'ArkShareGroup', ShareGroupEx = 'ArkShareGroup',
RebootNormal = 'reboot_normal',//无快速登录重新启动 RebootNormal = 'reboot_normal',//无快速登录重新启动

View File

@@ -0,0 +1,22 @@
import { ActionName } from '../types';
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
import {GetPacketStatusDepends} from "@/onebot/action/packet/GetPacketStatus";
const SchemaData = {
type: 'object',
properties: {
user_id: { type: ['number', 'string'] },
},
required: ['user_id'],
} as const satisfies JSONSchema;
type Payload = FromSchema<typeof SchemaData>;
export class FriendPoke extends GetPacketStatusDepends<Payload, any> {
actionName = ActionName.FriendPoke;
payloadSchema = SchemaData;
async _handle(payload: Payload) {
await this.core.apis.PacketApi.sendPokePacket(+payload.user_id);
}
}

View File

@@ -304,10 +304,10 @@ export class NapCatOneBot11Adapter {
}, },
m.msgId, m.msgId,
); );
if (m.sourceType == MsgSourceType.K_DOWN_SOURCETYPE_AIOINNER) { // if (m.sourceType == MsgSourceType.K_DOWN_SOURCETYPE_AIOINNER) {
await this.emitMsg(m) await this.emitMsg(m)
.catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e)); .catch(e => this.context.logger.logError.bind(this.context.logger)('处理消息失败', e));
} // }
} }
}; };
@@ -576,8 +576,6 @@ export class NapCatOneBot11Adapter {
this.networkManager.emitEvent(ob11Msg); this.networkManager.emitEvent(ob11Msg);
}).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e)); }).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e));
console.log('message', message);
this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => { this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => {
if (groupEvent) { if (groupEvent) {
// log("post group event", groupEvent); // log("post group event", groupEvent);

View File

@@ -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.0.3', 'napcat-update-button', 'secondary'), SettingButton('V3.0.6', 'napcat-update-button', 'secondary'),
), ),
]), ]),
SettingList([ SettingList([

View File

@@ -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.0.3", "napcat-update-button", "secondary") SettingButton("V3.0.6", "napcat-update-button", "secondary")
) )
]), ]),
SettingList([ SettingList([