mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-21 09:36:35 +00:00
Merge branch 'refs/heads/main' into laana
# Conflicts: # package.json # src/core/index.ts
This commit is contained in:
commit
9427cb4688
@ -34,7 +34,7 @@ NapCatQQ (aka 猫猫框架) 是现代化的基于 NTQQ 的 Bot 协议端实现
|
|||||||
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
[Telegram Link](https://t.me/+nLZEnpne-pQ1OWFl)
|
||||||
|
|
||||||
## 猫猫朋友
|
## 猫猫朋友
|
||||||
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot) 提供部分参考
|
感谢 [LLOneBot](https://github.com/LLOneBot/LLOneBot)
|
||||||
|
|
||||||
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
|
感谢 [Lagrange](https://github.com/LagrangeDev/Lagrange.Core) 对本项目的大力支持
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
"name": "NapCatQQ",
|
"name": "NapCatQQ",
|
||||||
"slug": "NapCat.Framework",
|
"slug": "NapCat.Framework",
|
||||||
"description": "高性能的 OneBot 11 协议实现",
|
"description": "高性能的 OneBot 11 协议实现",
|
||||||
"version": "2.6.24",
|
"version": "2.6.27",
|
||||||
"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": "2.6.24",
|
"version": "2.6.27",
|
||||||
"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",
|
||||||
|
@ -24,7 +24,9 @@ export class LRUCache<K, V> {
|
|||||||
} else if (this.cache.size >= this.capacity) {
|
} else if (this.cache.size >= this.capacity) {
|
||||||
// If the cache is full, remove the least recently used key (the first one in the map)
|
// If the cache is full, remove the least recently used key (the first one in the map)
|
||||||
const firstKey = this.cache.keys().next().value;
|
const firstKey = this.cache.keys().next().value;
|
||||||
this.cache.delete(firstKey);
|
if (firstKey !== undefined) {
|
||||||
|
this.cache.delete(firstKey);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
this.cache.set(key, value);
|
this.cache.set(key, value);
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -1 +1 @@
|
|||||||
export const napCatVersion = '2.6.24';
|
export const napCatVersion = '2.6.27';
|
||||||
|
@ -9,10 +9,22 @@ 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';
|
||||||
|
interface recvPacket
|
||||||
|
{
|
||||||
|
type: string,//仅recv
|
||||||
|
trace_id_md5?: string,
|
||||||
|
data: {
|
||||||
|
seq: number,
|
||||||
|
hex_data: string,
|
||||||
|
cmd: string
|
||||||
|
}
|
||||||
|
}
|
||||||
export class NTQQGroupApi {
|
export class NTQQGroupApi {
|
||||||
context: InstanceContext;
|
context: InstanceContext;
|
||||||
core: NapCatCore;
|
core: NapCatCore;
|
||||||
@ -20,6 +32,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 +46,11 @@ 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 () => {
|
||||||
|
// this.sendPocketRkey();
|
||||||
|
// }, 10000);
|
||||||
}
|
}
|
||||||
async getCoreAndBaseInfo(uids: string[]) {
|
async getCoreAndBaseInfo(uids: string[]) {
|
||||||
return await this.core.eventWrapper.callNoListenerEvent(
|
return await this.core.eventWrapper.callNoListenerEvent(
|
||||||
@ -41,6 +59,17 @@ export class NTQQGroupApi {
|
|||||||
uids,
|
uids,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
async sendPocketRkey() {
|
||||||
|
let hex = '08E7A00210CA01221D0A130A05080110CA011206A80602B006011A0208022206080A081408022A006001';
|
||||||
|
let ret = await this.core.apis.PacketApi.sendPacket('OidbSvcTrpcTcp.0x9067_202', hex, true);
|
||||||
|
//console.log('ret: ', ret);
|
||||||
|
}
|
||||||
|
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({
|
||||||
|
68
src/core/apis/packet.ts
Normal file
68
src/core/apis/packet.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
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((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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
4
src/core/external/appid.json
vendored
4
src/core/external/appid.json
vendored
@ -38,5 +38,9 @@
|
|||||||
"6.9.56-28418": {
|
"6.9.56-28418": {
|
||||||
"appid": 537249367,
|
"appid": 537249367,
|
||||||
"qua": "V1_MAC_NQ_6.9.56_28418_GW_B"
|
"qua": "V1_MAC_NQ_6.9.56_28418_GW_B"
|
||||||
|
},
|
||||||
|
"9.9.15-28498":{
|
||||||
|
"appid": 537249321,
|
||||||
|
"qua": "V1_WIN_NQ_9.9.15_28498_GW_B"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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": ""
|
||||||
}
|
}
|
14
src/core/external/offset.json
vendored
Normal file
14
src/core/external/offset.json
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"3.2.12-28418": {
|
||||||
|
"recv": "A0723E0",
|
||||||
|
"send": "A06EAE0"
|
||||||
|
},
|
||||||
|
"9.9.15-28418": {
|
||||||
|
"recv": "37A9004",
|
||||||
|
"send": "37A4BD0"
|
||||||
|
},
|
||||||
|
"9.9.15-28498": {
|
||||||
|
"recv": "37A9004",
|
||||||
|
"send": "37A4BD0"
|
||||||
|
}
|
||||||
|
}
|
123
src/core/helper/packet.ts
Normal file
123
src/core/helper/packet.ts
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import { LogWrapper } from "@/common/log";
|
||||||
|
import { LRUCache } from "@/common/lru-cache";
|
||||||
|
import WebSocket from "ws";
|
||||||
|
import { createHash } from "crypto";
|
||||||
|
|
||||||
|
export class PacketClient {
|
||||||
|
private websocket: WebSocket | undefined;
|
||||||
|
public isConnected: boolean = false;
|
||||||
|
private reconnectAttempts: number = 0;
|
||||||
|
private maxReconnectAttempts: number = 5;
|
||||||
|
//trace_id-type callback
|
||||||
|
private cb = new LRUCache<string, 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 {
|
||||||
|
try {
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.logError.bind(this.logger)(`Error attempting to reconnect: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async registerCallback(trace_id: string, type: string, callback: any): Promise<void> {
|
||||||
|
this.cb.put(createHash('md5').update(trace_id).digest('hex') + type, 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_md5 = json.trace_id_md5;
|
||||||
|
let action = json?.type ?? 'init';
|
||||||
|
let event = this.cb.get(trace_id_md5 + action);
|
||||||
|
if (event) {
|
||||||
|
await event(json.data);
|
||||||
|
}
|
||||||
|
//console.log("Received message:", json);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.logError.bind(this.logger)(`Error parsing message: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -31,6 +31,7 @@ import { NodeIKernelGroupListener, NodeIKernelMsgListener, NodeIKernelProfileLis
|
|||||||
import { proxiedListenerOf } from '@/common/proxy-handler';
|
import { proxiedListenerOf } from '@/common/proxy-handler';
|
||||||
import { NapCatEventChannel } from '@/core/events';
|
import { NapCatEventChannel } from '@/core/events';
|
||||||
|
|
||||||
|
import { NTQQPacketApi } from './apis/packet';
|
||||||
export * from './wrapper';
|
export * from './wrapper';
|
||||||
export * from './entities';
|
export * from './entities';
|
||||||
export * from './services';
|
export * from './services';
|
||||||
@ -84,17 +85,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');
|
||||||
@ -328,6 +330,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
|
||||||
|
});
|
||||||
|
}
|
31
src/core/proto/Poke.ts
Normal file
31
src/core/proto/Poke.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import { MessageType, ScalarType, BinaryWriter } from '@protobuf-ts/runtime';
|
||||||
|
|
||||||
|
export const OidbSvcTrpcTcpBase = new MessageType("oidb_svc_trpctcp_base", [
|
||||||
|
{ no: 1, name: "command", kind: "scalar", T: ScalarType.UINT32 },
|
||||||
|
{ no: 2, name: "subcommand", kind: "scalar", T: ScalarType.UINT32, 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", [
|
||||||
|
{ no: 1, name: "uin", kind: "scalar", T: ScalarType.UINT32 },
|
||||||
|
{ no: 2, name: "groupuin", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
||||||
|
{ no: 5, name: "frienduin", kind: "scalar", T: ScalarType.UINT32, opt: true },
|
||||||
|
{ no: 6, name: "ext", kind: "scalar", T: ScalarType.UINT32 }
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function encodeGroupPoke(groupUin: number, PeerUin: number) {
|
||||||
|
let Body = OidbSvcTrpcTcp0XED3_1.toBinary
|
||||||
|
({
|
||||||
|
uin: PeerUin,
|
||||||
|
groupuin: groupUin,
|
||||||
|
ext: 0
|
||||||
|
});
|
||||||
|
//console.log(Body)
|
||||||
|
return OidbSvcTrpcTcpBase.toBinary
|
||||||
|
({
|
||||||
|
command: 0xed3,
|
||||||
|
subcommand: 1,
|
||||||
|
body: Body
|
||||||
|
});
|
||||||
|
}
|
@ -4,7 +4,7 @@ import { dlopen } from "process";
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
export class Native {
|
export class Native {
|
||||||
platform: string;
|
platform: string;
|
||||||
supportedPlatforms = ['win32'];
|
supportedPlatforms = [''];
|
||||||
MoeHooExport: any = { exports: {} };
|
MoeHooExport: any = { exports: {} };
|
||||||
recallHookEnabled: boolean = false;
|
recallHookEnabled: boolean = false;
|
||||||
inited = true;
|
inited = true;
|
||||||
|
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;
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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('V2.6.24', 'napcat-update-button', 'secondary'),
|
SettingButton('V2.6.27', '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("V2.6.24", "napcat-update-button", "secondary")
|
SettingButton("V2.6.27", "napcat-update-button", "secondary")
|
||||||
)
|
)
|
||||||
]),
|
]),
|
||||||
SettingList([
|
SettingList([
|
||||||
|
Loading…
x
Reference in New Issue
Block a user