mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2024-11-21 09:36:35 +00:00
fix: new server
This commit is contained in:
parent
a97437a6e5
commit
69c477b104
1
config.json
Normal file
1
config.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"ip": "127.0.0.1", "port": 8086}
|
@ -56,10 +56,7 @@ export class NTQQGroupApi {
|
|||||||
async sendPacketPoke(group: string, peer: string) {
|
async sendPacketPoke(group: string, peer: string) {
|
||||||
let data = encodeGroupPoke(group, peer);
|
let data = encodeGroupPoke(group, peer);
|
||||||
let hex = Buffer.from(data).toString('hex');
|
let hex = Buffer.from(data).toString('hex');
|
||||||
let retdata = await this.core.apis.PacketApi.sendPacket('OidbSvcTrpcTcp.0xed3_1', hex);
|
let retdata = await this.core.apis.PacketApi.sendPacket('OidbSvcTrpcTcp.0xed3_1', hex, true);
|
||||||
//await RequestUtil.HttpGetJson('http://127.0.0.1:8086/send', 'POST', { data: hex }, { 'Content-Type': 'application/json' }, false, true);
|
|
||||||
//let ret = await this.core.context.session.getMsgService().sendSsoCmdReqByContend('LightAppSvc.mini_app_i', hex.slice(0, hex.length / 2));
|
|
||||||
// let ret = await this.core.context.session.getMsgService().sendSsoCmdReqByContend('OidbSvcTrpcTcp.0xfe1_2', hex.toString('hex'));
|
|
||||||
console.log('sendPacketPoke', retdata);
|
console.log('sendPacketPoke', retdata);
|
||||||
}
|
}
|
||||||
async fetchGroupEssenceList(groupCode: string) {
|
async fetchGroupEssenceList(groupCode: string) {
|
||||||
|
@ -2,6 +2,7 @@ import { InstanceContext, NapCatCore } from '..';
|
|||||||
import { RequestUtil } from '@/common/request';
|
import { RequestUtil } from '@/common/request';
|
||||||
import offset from '@/core/external/offset.json';
|
import offset from '@/core/external/offset.json';
|
||||||
import * as crypto from 'crypto';
|
import * as crypto from 'crypto';
|
||||||
|
import { PacketClient } from '../helper/packet';
|
||||||
|
|
||||||
interface OffsetType {
|
interface OffsetType {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
@ -17,30 +18,26 @@ export class NTQQPacketApi {
|
|||||||
serverUrl: string | undefined;
|
serverUrl: string | undefined;
|
||||||
qqversion: string | undefined;
|
qqversion: string | undefined;
|
||||||
isInit: boolean = false;
|
isInit: boolean = false;
|
||||||
|
PacketClient: PacketClient | undefined;
|
||||||
constructor(context: InstanceContext, core: NapCatCore) {
|
constructor(context: InstanceContext, core: NapCatCore) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.core = core;
|
this.core = core;
|
||||||
this.InitSendPacket('127.0.0.1:8086', '9.9.15-28418', '1001').then().catch();
|
this.InitSendPacket('127.0.0.1:8086', '9.9.15-28418', '1001').then().catch(this.core.context.logger.logError.bind(this.core.context.logger));
|
||||||
}
|
}
|
||||||
async InitSendPacket(serverUrl: string, qqversion: string, uin: string) {
|
async InitSendPacket(serverUrl: string, qqversion: string, uin: string) {
|
||||||
this.serverUrl = serverUrl;
|
this.serverUrl = serverUrl;
|
||||||
this.qqversion = qqversion;
|
this.qqversion = qqversion;
|
||||||
let offsetTable: OffsetType = offset;
|
let offsetTable: OffsetType = offset;
|
||||||
if (!offsetTable[qqversion]) return false;
|
if (!offsetTable[qqversion]) return false;
|
||||||
let url = 'http://' + this.serverUrl + '/init';
|
let url = 'ws://' + this.serverUrl + '/ws';
|
||||||
let postdata = { recv: offsetTable[qqversion].recv, send: offsetTable[qqversion].send, qqver: qqversion, uin: uin, pid: process.pid };
|
// let postdata = { recv: offsetTable[qqversion].recv, send: offsetTable[qqversion].send, qqver: qqversion, uin: uin, pid: process.pid };
|
||||||
try {
|
this.PacketClient = new PacketClient(url, this.core.context.logger);
|
||||||
let ret = await RequestUtil.HttpGetJson<any>(url, 'POST', postdata, { 'Content-Type': 'application/json' }, true, true);
|
await this.PacketClient.connect();
|
||||||
if (ret.status !== 'ok') throw new Error('InitSendPacket failed' + JSON.stringify(ret, null, 2));
|
await this.PacketClient.init(process.pid, offsetTable[qqversion].recv, offsetTable[qqversion].send);
|
||||||
} catch (error) {
|
|
||||||
let logger = this.core.context.logger;
|
|
||||||
logger.logError.bind(logger)('InitSendPacket', error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
this.isInit = true;
|
this.isInit = true;
|
||||||
return this.isInit;
|
return this.isInit;
|
||||||
}
|
}
|
||||||
async randText(len: number) {
|
randText(len: number) {
|
||||||
let text = '';
|
let text = '';
|
||||||
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
let possible = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||||
for (let i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
@ -48,25 +45,13 @@ export class NTQQPacketApi {
|
|||||||
}
|
}
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
async sendPacket(cmd: string, data: string, rep = false) {
|
async sendPacket(cmd: string, data: string, rsp = false) {
|
||||||
return new Promise(async (resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
//获取data的HASH
|
|
||||||
let md5 = crypto.createHash('md5').update(data).digest('hex');
|
let md5 = crypto.createHash('md5').update(data).digest('hex');
|
||||||
let url = 'http://' + this.serverUrl + '/send';
|
let trace_id = (this.randText(4) + md5 + data).slice(0, data.length / 2);
|
||||||
let geturl = 'http://' + this.serverUrl + '/get';
|
this.PacketClient?.sendCommand(cmd, data, trace_id, rsp, 5000, async () => {
|
||||||
let trace_id = (await this.randText(4) + md5 + data).slice(0, data.length / 2);
|
await this.core.context.session.getMsgService().sendSsoCmdReqByContend(cmd, trace_id);
|
||||||
let postdata = { data: data, trace_id: trace_id, cmd: cmd };
|
}).then((res) => resolve(res)).catch((e) => reject(e));
|
||||||
|
|
||||||
RequestUtil.HttpGetJson<any>(url, 'POST', postdata, { 'Content-Type': 'application/json' }, true, true).then((res) => {
|
|
||||||
if (!rep) {
|
|
||||||
this.core.context.session.getMsgService().sendSsoCmdReqByContend(cmd, trace_id).then(e => resolve(res)).catch(e => reject(e))
|
|
||||||
} else {
|
|
||||||
let getpostdata = { data: data, trace_id: trace_id, cmd: cmd };
|
|
||||||
RequestUtil.HttpGetJson<any>(geturl, 'POST', getpostdata, { 'Content-Type': 'application/json' }, true, true).then((rsp) => {
|
|
||||||
resolve(rsp)
|
|
||||||
}).catch((e) => reject(e));
|
|
||||||
}
|
|
||||||
}).catch((e) => reject(e));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
115
src/core/helper/packet.ts
Normal file
115
src/core/helper/packet.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import { LogWrapper } from "@/common/log";
|
||||||
|
import { LRUCache } from "@/common/lru-cache";
|
||||||
|
import WebSocket from "ws";
|
||||||
|
|
||||||
|
export class PacketClient {
|
||||||
|
private websocket: WebSocket | undefined;
|
||||||
|
private 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.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(), 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));
|
||||||
|
this.registerCallback(trace_id, 'send', (json: any) => {
|
||||||
|
sendcb(json);
|
||||||
|
if (!rsp) {
|
||||||
|
clearTimeout(timeoutHandle);
|
||||||
|
resolve(json);
|
||||||
|
} else {
|
||||||
|
this.registerCallback(trace_id, 'recv', (json: any) => {
|
||||||
|
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}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user