mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
@@ -61,7 +61,7 @@ export class RequestUtil {
|
|||||||
const options = {
|
const options = {
|
||||||
hostname: option.hostname,
|
hostname: option.hostname,
|
||||||
port: option.port,
|
port: option.port,
|
||||||
path: option.href,
|
path: option.pathname + option.search,
|
||||||
method: method,
|
method: method,
|
||||||
headers: headers,
|
headers: headers,
|
||||||
};
|
};
|
||||||
|
@@ -9,9 +9,12 @@ import {
|
|||||||
MemberExtSourceType,
|
MemberExtSourceType,
|
||||||
NapCatCore,
|
NapCatCore,
|
||||||
} from '@/core';
|
} from '@/core';
|
||||||
import { isNumeric, solveAsyncProblem } from '@/common/helper';
|
import { isNumeric, sleep, solveAsyncProblem } from '@/common/helper';
|
||||||
import { LimitedHashTable } from '@/common/message-unique';
|
import { LimitedHashTable } from '@/common/message-unique';
|
||||||
import { NTEventWrapper } from '@/common/event';
|
import { NTEventWrapper } from '@/common/event';
|
||||||
|
import { encodeGroupPoke } from '../proto/Poke';
|
||||||
|
import { randomUUID } from 'crypto';
|
||||||
|
import { RequestUtil } from '@/common/request';
|
||||||
|
|
||||||
export class NTQQGroupApi {
|
export class NTQQGroupApi {
|
||||||
context: InstanceContext;
|
context: InstanceContext;
|
||||||
@@ -20,6 +23,7 @@ export class NTQQGroupApi {
|
|||||||
groupMemberCache: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>();
|
groupMemberCache: Map<string, Map<string, GroupMember>> = new Map<string, Map<string, GroupMember>>();
|
||||||
groups: Group[] = [];
|
groups: Group[] = [];
|
||||||
essenceLRU = new LimitedHashTable<number, string>(1000);
|
essenceLRU = new LimitedHashTable<number, string>(1000);
|
||||||
|
session: any;
|
||||||
|
|
||||||
constructor(context: InstanceContext, core: NapCatCore) {
|
constructor(context: InstanceContext, core: NapCatCore) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
@@ -33,6 +37,14 @@ export class NTQQGroupApi {
|
|||||||
this.groupCache.set(group.groupCode, group);
|
this.groupCache.set(group.groupCode, group);
|
||||||
}
|
}
|
||||||
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
|
this.context.logger.logDebug(`加载${this.groups.length}个群组缓存完成`);
|
||||||
|
console.log('pid', process.pid);
|
||||||
|
// this.session = await frida.attach(process.pid);
|
||||||
|
// setTimeout(async () => {
|
||||||
|
// let data = Buffer.from('089601', 'hex').toString('utf-8');//optional int32 a = 1;
|
||||||
|
// console.log('data', Buffer.from(data).toString('hex'));
|
||||||
|
// let ret = await this.core.context.session.getMsgService().sendSsoCmdReqByContend("OidbSvcTrpcTcp.0xfe1_2", data);
|
||||||
|
// console.log('sendSsoCmdReqByContend', ret);
|
||||||
|
// }, 20000);
|
||||||
}
|
}
|
||||||
async getCoreAndBaseInfo(uids: string[]) {
|
async getCoreAndBaseInfo(uids: string[]) {
|
||||||
return await this.core.eventWrapper.callNoListenerEvent(
|
return await this.core.eventWrapper.callNoListenerEvent(
|
||||||
@@ -41,6 +53,12 @@ export class NTQQGroupApi {
|
|||||||
uids,
|
uids,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
async sendPacketPoke(group: number, peer: number) {
|
||||||
|
let data = encodeGroupPoke(group, peer);
|
||||||
|
let hex = Buffer.from(data).toString('hex');
|
||||||
|
let retdata = await this.core.apis.PacketApi.sendPacket('OidbSvcTrpcTcp.0xed3_1', hex, false);
|
||||||
|
//console.log('sendPacketPoke', retdata);
|
||||||
|
}
|
||||||
async fetchGroupEssenceList(groupCode: string) {
|
async fetchGroupEssenceList(groupCode: string) {
|
||||||
const pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
const pskey = (await this.core.apis.UserApi.getPSkey(['qun.qq.com'])).domainPskeyMap.get('qun.qq.com')!;
|
||||||
return this.context.session.getGroupService().fetchGroupEssenceList({
|
return this.context.session.getGroupService().fetchGroupEssenceList({
|
||||||
|
77
src/core/apis/packet.ts
Normal file
77
src/core/apis/packet.ts
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import { InstanceContext, NapCatCore } from '..';
|
||||||
|
import { RequestUtil } from '@/common/request';
|
||||||
|
import offset from '@/core/external/offset.json';
|
||||||
|
import * as crypto from 'crypto';
|
||||||
|
import { PacketClient } from '../helper/packet';
|
||||||
|
|
||||||
|
interface OffsetType {
|
||||||
|
[key: string]: {
|
||||||
|
recv: string;
|
||||||
|
send: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const typedOffset: OffsetType = offset;
|
||||||
|
export class NTQQPacketApi {
|
||||||
|
context: InstanceContext;
|
||||||
|
core: NapCatCore;
|
||||||
|
serverUrl: string | undefined;
|
||||||
|
qqversion: string | undefined;
|
||||||
|
isInit: boolean = false;
|
||||||
|
PacketClient: PacketClient | undefined;
|
||||||
|
constructor(context: InstanceContext, core: NapCatCore) {
|
||||||
|
this.context = context;
|
||||||
|
this.core = core;
|
||||||
|
let config = this.core.configLoader.configData;
|
||||||
|
if (config && config.packetServer && config.packetServer.length > 0) {
|
||||||
|
let serverurl = this.core.configLoader.configData.packetServer ?? '127.0.0.1:8086';
|
||||||
|
this.InitSendPacket(serverurl, this.context.basicInfoWrapper.getFullQQVesion())
|
||||||
|
.then()
|
||||||
|
.catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async InitSendPacket(serverUrl: string, qqversion: string) {
|
||||||
|
this.serverUrl = serverUrl;
|
||||||
|
this.qqversion = qqversion;
|
||||||
|
let offsetTable: OffsetType = offset;
|
||||||
|
if (!offsetTable[qqversion]) return false;
|
||||||
|
let url = 'ws://' + this.serverUrl + '/ws';
|
||||||
|
this.PacketClient = new PacketClient(url, this.core.context.logger);
|
||||||
|
await this.PacketClient.connect();
|
||||||
|
await this.PacketClient.init(process.pid, offsetTable[qqversion].recv, offsetTable[qqversion].send);
|
||||||
|
this.isInit = true;
|
||||||
|
return this.isInit;
|
||||||
|
}
|
||||||
|
randText(len: number) {
|
||||||
|
let text = '';
|
||||||
|
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
|
for (let i = 0; i < len; i++) {
|
||||||
|
text += possible.charAt(Math.floor(Math.random() * possible.length));
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
async sendPacket(cmd: string, data: string, rsp = false) {
|
||||||
|
// wtfk tx
|
||||||
|
// 校验失败和异常 可能返回undefined
|
||||||
|
return new Promise<undefined | {
|
||||||
|
type: string,//仅recv含有data
|
||||||
|
trace_id: string,
|
||||||
|
data: {
|
||||||
|
trace_id: string,
|
||||||
|
seq: number,
|
||||||
|
hex_data: string,
|
||||||
|
cmd: string
|
||||||
|
}
|
||||||
|
}>((resolve, reject) => {
|
||||||
|
if (!this.isInit || !this.PacketClient?.isConnected) {
|
||||||
|
this.core.context.logger.logError('PacketClient is not init');
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
let md5 = crypto.createHash('md5').update(data).digest('hex');
|
||||||
|
let trace_id = (this.randText(4) + md5 + data).slice(0, data.length / 2);
|
||||||
|
this.PacketClient?.sendCommand(cmd, data, trace_id, rsp, 5000, async () => {
|
||||||
|
await this.core.context.session.getMsgService().sendSsoCmdReqByContend(cmd, trace_id);
|
||||||
|
}).then((res) => resolve(res)).catch((e) => reject(e));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
3
src/core/external/napcat.json
vendored
3
src/core/external/napcat.json
vendored
@@ -2,5 +2,6 @@
|
|||||||
"fileLog": true,
|
"fileLog": true,
|
||||||
"consoleLog": true,
|
"consoleLog": true,
|
||||||
"fileLogLevel": "debug",
|
"fileLogLevel": "debug",
|
||||||
"consoleLogLevel": "info"
|
"consoleLogLevel": "info",
|
||||||
|
"packetServer": ""
|
||||||
}
|
}
|
10
src/core/external/offset.json
vendored
Normal file
10
src/core/external/offset.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"9.9.15-28418":{
|
||||||
|
"recv": "37A9004",
|
||||||
|
"send": "37A4BD0"
|
||||||
|
},
|
||||||
|
"9.9.15-28498":{
|
||||||
|
"recv": "37A9004",
|
||||||
|
"send": "37A4BD0"
|
||||||
|
}
|
||||||
|
}
|
116
src/core/helper/packet.ts
Normal file
116
src/core/helper/packet.ts
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
import { LogWrapper } from "@/common/log";
|
||||||
|
import { LRUCache } from "@/common/lru-cache";
|
||||||
|
import WebSocket from "ws";
|
||||||
|
|
||||||
|
export class PacketClient {
|
||||||
|
private websocket: WebSocket | undefined;
|
||||||
|
public isConnected: boolean = false;
|
||||||
|
private reconnectAttempts: number = 0;
|
||||||
|
private maxReconnectAttempts: number = 5;
|
||||||
|
private cb = new LRUCache<string, { type: string, callback: any }>(500);
|
||||||
|
constructor(private url: string, public logger: LogWrapper) { }
|
||||||
|
|
||||||
|
connect(): Promise<void> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.logger.log.bind(this.logger)(`Attempting to connect to ${this.url}`);
|
||||||
|
this.websocket = new WebSocket(this.url);
|
||||||
|
this.websocket.on('error', (err) => this.logger.logError.bind(this.logger)('[Core] [Packet Server] Error:', err.message));
|
||||||
|
this.websocket.onopen = () => {
|
||||||
|
this.isConnected = true;
|
||||||
|
this.reconnectAttempts = 0;
|
||||||
|
this.logger.log.bind(this.logger)(`Connected to ${this.url}`);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
this.websocket.onerror = (error) => {
|
||||||
|
this.logger.logError.bind(this.logger)(`WebSocket error: ${error}`);
|
||||||
|
reject(error);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.websocket.onmessage = (event) => {
|
||||||
|
// const message = JSON.parse(event.data.toString());
|
||||||
|
// console.log("Received message:", message);
|
||||||
|
this.handleMessage(event.data);
|
||||||
|
};
|
||||||
|
|
||||||
|
this.websocket.onclose = () => {
|
||||||
|
this.isConnected = false;
|
||||||
|
this.logger.logWarn.bind(this.logger)(`Disconnected from ${this.url}`);
|
||||||
|
this.attemptReconnect();
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private attemptReconnect(): void {
|
||||||
|
if (this.reconnectAttempts < this.maxReconnectAttempts) {
|
||||||
|
this.reconnectAttempts++;
|
||||||
|
this.logger.logError.bind(this.logger)(`Reconnecting attempt ${this.reconnectAttempts}`);
|
||||||
|
setTimeout(() => this.connect().then().catch(), 1000 * this.reconnectAttempts);
|
||||||
|
} else {
|
||||||
|
this.logger.logError.bind(this.logger)(`Max reconnect attempts reached. Could not reconnect to ${this.url}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async registerCallback(trace_id: string, type: string, callback: any): Promise<void> {
|
||||||
|
this.cb.put(trace_id, { type: type, callback: callback });
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(pid: number, recv: string, send: string): Promise<void> {
|
||||||
|
if (!this.isConnected || !this.websocket) {
|
||||||
|
throw new Error("WebSocket is not connected");
|
||||||
|
}
|
||||||
|
|
||||||
|
const initMessage = {
|
||||||
|
action: 'init',
|
||||||
|
pid: pid,
|
||||||
|
recv: recv,
|
||||||
|
send: send
|
||||||
|
};
|
||||||
|
this.websocket.send(JSON.stringify(initMessage));
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendCommand(cmd: string, data: string, trace_id: string, rsp: boolean = false, timeout: number = 5000, sendcb: any = () => { }): Promise<any> {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
if (!this.isConnected || !this.websocket) {
|
||||||
|
throw new Error("WebSocket is not connected");
|
||||||
|
}
|
||||||
|
const commandMessage = {
|
||||||
|
action: 'send',
|
||||||
|
cmd: cmd,
|
||||||
|
data: data,
|
||||||
|
trace_id: trace_id
|
||||||
|
};
|
||||||
|
|
||||||
|
this.websocket.send(JSON.stringify(commandMessage));
|
||||||
|
if (rsp) {
|
||||||
|
this.registerCallback(trace_id, 'recv', (json: any) => {
|
||||||
|
clearTimeout(timeoutHandle);
|
||||||
|
resolve(json);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.registerCallback(trace_id, 'send', (json: any) => {
|
||||||
|
sendcb(json);
|
||||||
|
if (!rsp) {
|
||||||
|
clearTimeout(timeoutHandle);
|
||||||
|
resolve(json);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const timeoutHandle = setTimeout(() => {
|
||||||
|
reject(new Error(`sendCommand timed out after ${timeout} ms`));
|
||||||
|
}, timeout);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
private async handleMessage(message: any): Promise<void> {
|
||||||
|
try {
|
||||||
|
|
||||||
|
let json = JSON.parse(message.toString());
|
||||||
|
let trace_id = json.trace_id;
|
||||||
|
let event = this.cb.get(trace_id);
|
||||||
|
if (event?.type == 'all' || event?.type == json.type) {
|
||||||
|
await event?.callback(json.data);
|
||||||
|
}
|
||||||
|
//console.log("Received message:", json);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.logError.bind(this.logger)(`Error parsing message: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -29,6 +29,7 @@ import { NapCatConfigLoader } from '@/core/helper/config';
|
|||||||
import os from 'node:os';
|
import os from 'node:os';
|
||||||
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
|
import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
|
||||||
import { proxiedListenerOf } from '@/common/proxy-handler';
|
import { proxiedListenerOf } from '@/common/proxy-handler';
|
||||||
|
import { NTQQPacketApi } from './apis/packet';
|
||||||
export * from './wrapper';
|
export * from './wrapper';
|
||||||
export * from './entities';
|
export * from './entities';
|
||||||
export * from './services';
|
export * from './services';
|
||||||
@@ -80,17 +81,18 @@ export class NapCatCore {
|
|||||||
this.context = context;
|
this.context = context;
|
||||||
this.util = this.context.wrapper.NodeQQNTWrapperUtil;
|
this.util = this.context.wrapper.NodeQQNTWrapperUtil;
|
||||||
this.eventWrapper = new NTEventWrapper(context.session);
|
this.eventWrapper = new NTEventWrapper(context.session);
|
||||||
|
this.configLoader = new NapCatConfigLoader(this, this.context.pathWrapper.configPath);
|
||||||
this.apis = {
|
this.apis = {
|
||||||
FileApi: new NTQQFileApi(this.context, this),
|
FileApi: new NTQQFileApi(this.context, this),
|
||||||
SystemApi: new NTQQSystemApi(this.context, this),
|
SystemApi: new NTQQSystemApi(this.context, this),
|
||||||
CollectionApi: new NTQQCollectionApi(this.context, this),
|
CollectionApi: new NTQQCollectionApi(this.context, this),
|
||||||
|
PacketApi: new NTQQPacketApi(this.context, this),
|
||||||
WebApi: new NTQQWebApi(this.context, this),
|
WebApi: new NTQQWebApi(this.context, this),
|
||||||
FriendApi: new NTQQFriendApi(this.context, this),
|
FriendApi: new NTQQFriendApi(this.context, this),
|
||||||
MsgApi: new NTQQMsgApi(this.context, this),
|
MsgApi: new NTQQMsgApi(this.context, this),
|
||||||
UserApi: new NTQQUserApi(this.context, this),
|
UserApi: new NTQQUserApi(this.context, this),
|
||||||
GroupApi: new NTQQGroupApi(this.context, this),
|
GroupApi: new NTQQGroupApi(this.context, this),
|
||||||
};
|
};
|
||||||
this.configLoader = new NapCatConfigLoader(this, this.context.pathWrapper.configPath);
|
|
||||||
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
this.NapCatDataPath = path.join(this.dataPath, 'NapCat');
|
||||||
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
fs.mkdirSync(this.NapCatDataPath, { recursive: true });
|
||||||
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
this.NapCatTempPath = path.join(this.NapCatDataPath, 'temp');
|
||||||
@@ -322,6 +324,7 @@ export interface InstanceContext {
|
|||||||
export interface StableNTApiWrapper {
|
export interface StableNTApiWrapper {
|
||||||
FileApi: NTQQFileApi,
|
FileApi: NTQQFileApi,
|
||||||
SystemApi: NTQQSystemApi,
|
SystemApi: NTQQSystemApi,
|
||||||
|
PacketApi: NTQQPacketApi,
|
||||||
CollectionApi: NTQQCollectionApi,
|
CollectionApi: NTQQCollectionApi,
|
||||||
WebApi: NTQQWebApi,
|
WebApi: NTQQWebApi,
|
||||||
FriendApi: NTQQFriendApi,
|
FriendApi: NTQQFriendApi,
|
||||||
|
21
src/core/proto/Oidb.fe1_2.ts
Normal file
21
src/core/proto/Oidb.fe1_2.ts
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
import { MessageType, ScalarType } from "@protobuf-ts/runtime";
|
||||||
|
import { OidbSvcTrpcTcpBase } from "./Poke";
|
||||||
|
|
||||||
|
export const OidbSvcTrpcTcp0XFE1_2 = new MessageType("oidb_svc_trpctcp_0xfe1_2", [
|
||||||
|
{ no: 1, name: "uin", kind: "scalar", T: ScalarType.UINT32 },
|
||||||
|
{ no: 3, name: "key", kind: "scalar", T: ScalarType.BYTES, opt: true }
|
||||||
|
]);
|
||||||
|
export function encode_packet_0xfe1_2(PeerUin: string) {
|
||||||
|
let Body = OidbSvcTrpcTcp0XFE1_2.toBinary
|
||||||
|
({
|
||||||
|
uin: parseInt(PeerUin),
|
||||||
|
key: new Uint8Array([0x00, 0x00, 0x00, 0x00])
|
||||||
|
});
|
||||||
|
return OidbSvcTrpcTcpBase.toBinary
|
||||||
|
({
|
||||||
|
command: 0xfe1,
|
||||||
|
subcommand: 2,
|
||||||
|
body: Body,
|
||||||
|
isreserved: 1
|
||||||
|
});
|
||||||
|
}
|
@@ -3,7 +3,8 @@ import { MessageType, ScalarType, BinaryWriter } from '@protobuf-ts/runtime';
|
|||||||
export const OidbSvcTrpcTcpBase = new MessageType("oidb_svc_trpctcp_base", [
|
export const OidbSvcTrpcTcpBase = new MessageType("oidb_svc_trpctcp_base", [
|
||||||
{ no: 1, name: "command", kind: "scalar", T: ScalarType.UINT32 },
|
{ no: 1, name: "command", kind: "scalar", T: ScalarType.UINT32 },
|
||||||
{ no: 2, name: "subcommand", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
{ no: 2, name: "subcommand", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
||||||
{ no: 4, name: "body", kind: "scalar", T: ScalarType.BYTES, opt: true }
|
{ no: 4, name: "body", kind: "scalar", T: ScalarType.BYTES, opt: true },
|
||||||
|
{ no: 12, name: "isreserved", kind: "scalar", T: ScalarType.INT32, opt: true }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export const OidbSvcTrpcTcp0XED3_1 = new MessageType("oidb_svc_trpctcp_0xed3_1", [
|
export const OidbSvcTrpcTcp0XED3_1 = new MessageType("oidb_svc_trpctcp_0xed3_1", [
|
||||||
@@ -13,11 +14,11 @@ export const OidbSvcTrpcTcp0XED3_1 = new MessageType("oidb_svc_trpctcp_0xed3_1",
|
|||||||
{ no: 6, name: "ext", kind: "scalar", T: ScalarType.UINT32 }
|
{ no: 6, name: "ext", kind: "scalar", T: ScalarType.UINT32 }
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export function encodeGroupPoke(groupUin: string, PeerUin: string) {
|
export function encodeGroupPoke(groupUin: number, PeerUin: number) {
|
||||||
let Body = OidbSvcTrpcTcp0XED3_1.toBinary
|
let Body = OidbSvcTrpcTcp0XED3_1.toBinary
|
||||||
({
|
({
|
||||||
uin: parseInt(PeerUin),
|
uin: PeerUin,
|
||||||
groupuin: parseInt(groupUin),
|
groupuin: groupUin,
|
||||||
ext: 0
|
ext: 0
|
||||||
});
|
});
|
||||||
//console.log(Body)
|
//console.log(Body)
|
||||||
|
26
src/onebot/action/group/GroupPoke.ts
Normal file
26
src/onebot/action/group/GroupPoke.ts
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import BaseAction from '../BaseAction';
|
||||||
|
import { ActionName } from '../types';
|
||||||
|
import { FromSchema, JSONSchema } from 'json-schema-to-ts';
|
||||||
|
// no_cache get时传字符串
|
||||||
|
const SchemaData = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
group_id: { type: ['number', 'string'] },
|
||||||
|
user_id: { type: ['number', 'string'] },
|
||||||
|
},
|
||||||
|
required: ['group_id', 'user_id'],
|
||||||
|
} as const satisfies JSONSchema;
|
||||||
|
|
||||||
|
type Payload = FromSchema<typeof SchemaData>;
|
||||||
|
|
||||||
|
export class GroupPoke extends BaseAction<Payload, any> {
|
||||||
|
actionName = ActionName.GroupPoke;
|
||||||
|
payloadSchema = SchemaData;
|
||||||
|
|
||||||
|
async _handle(payload: Payload) {
|
||||||
|
if (!this.core.apis.PacketApi.PacketClient?.isConnected) {
|
||||||
|
throw new Error('PacketClient is not init');
|
||||||
|
}
|
||||||
|
this.core.apis.GroupApi.sendPacketPoke(+payload.group_id, +payload.user_id);
|
||||||
|
}
|
||||||
|
}
|
@@ -84,6 +84,7 @@ import { GetGroupFileSystemInfo } from '@/onebot/action/go-cqhttp/GetGroupFileSy
|
|||||||
import { GetGroupRootFiles } from '@/onebot/action/go-cqhttp/GetGroupRootFiles';
|
import { GetGroupRootFiles } from '@/onebot/action/go-cqhttp/GetGroupRootFiles';
|
||||||
import { GetGroupFilesByFolder } from '@/onebot/action/go-cqhttp/GetGroupFilesByFolder';
|
import { GetGroupFilesByFolder } from '@/onebot/action/go-cqhttp/GetGroupFilesByFolder';
|
||||||
import { GetGroupSystemMsg } from './system/GetSystemMsg';
|
import { GetGroupSystemMsg } from './system/GetSystemMsg';
|
||||||
|
import { GroupPoke } from './group/GroupPoke';
|
||||||
|
|
||||||
|
|
||||||
export type ActionMap = Map<string, BaseAction<any, any>>;
|
export type ActionMap = Map<string, BaseAction<any, any>>;
|
||||||
@@ -180,6 +181,7 @@ export function createActionMap(obContext: NapCatOneBot11Adapter, core: NapCatCo
|
|||||||
new GetGroupFilesByFolder(obContext, core),
|
new GetGroupFilesByFolder(obContext, core),
|
||||||
new GetGroupSystemMsg(obContext, core),
|
new GetGroupSystemMsg(obContext, core),
|
||||||
new FetchUserProfileLike(obContext, core),
|
new FetchUserProfileLike(obContext, core),
|
||||||
|
new GroupPoke(obContext, core),
|
||||||
];
|
];
|
||||||
const actionMap = new Map();
|
const actionMap = new Map();
|
||||||
for (const action of actionHandlers) {
|
for (const action of actionHandlers) {
|
||||||
|
@@ -16,6 +16,7 @@ export interface InvalidCheckResult {
|
|||||||
export enum ActionName {
|
export enum ActionName {
|
||||||
// 以下为扩展napcat扩展
|
// 以下为扩展napcat扩展
|
||||||
Unknown = 'unknown',
|
Unknown = 'unknown',
|
||||||
|
GroupPoke = 'group_poke',
|
||||||
SharePeer = 'ArkSharePeer',
|
SharePeer = 'ArkSharePeer',
|
||||||
ShareGroupEx = 'ArkShareGroup',
|
ShareGroupEx = 'ArkShareGroup',
|
||||||
RebootNormal = 'reboot_normal',//无快速登录重新启动
|
RebootNormal = 'reboot_normal',//无快速登录重新启动
|
||||||
|
@@ -21,6 +21,7 @@ import { OB11GroupTitleEvent } from '@/onebot/event/notice/OB11GroupTitleEvent';
|
|||||||
import { FileNapCatOneBotUUID } from '@/common/helper';
|
import { FileNapCatOneBotUUID } from '@/common/helper';
|
||||||
import { pathToFileURL } from 'node:url';
|
import { pathToFileURL } from 'node:url';
|
||||||
|
|
||||||
|
|
||||||
export class OneBotGroupApi {
|
export class OneBotGroupApi {
|
||||||
obContext: NapCatOneBot11Adapter;
|
obContext: NapCatOneBot11Adapter;
|
||||||
core: NapCatCore;
|
core: NapCatCore;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"http": {
|
"http": {
|
||||||
"enable": false,
|
"enable": true,
|
||||||
"host": "",
|
"host": "",
|
||||||
"port": 3000,
|
"port": 3000,
|
||||||
"secret": "",
|
"secret": "",
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
"postUrls": []
|
"postUrls": []
|
||||||
},
|
},
|
||||||
"ws": {
|
"ws": {
|
||||||
"enable": false,
|
"enable": true,
|
||||||
"host": "",
|
"host": "",
|
||||||
"port": 3001
|
"port": 3001
|
||||||
},
|
},
|
||||||
|
@@ -540,6 +540,10 @@ export class NapCatOneBot11Adapter {
|
|||||||
if (isSelfMsg) {
|
if (isSelfMsg) {
|
||||||
ob11Msg.target_id = parseInt(message.peerUin);
|
ob11Msg.target_id = parseInt(message.peerUin);
|
||||||
}
|
}
|
||||||
|
// if(ob11Msg.raw_message.startsWith('!poke')){
|
||||||
|
// console.log('poke',message.peerUin, message.senderUin);
|
||||||
|
// this.core.apis.GroupApi.sendPacketPoke(message.peerUin, message.senderUin);
|
||||||
|
// }
|
||||||
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));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user