From be2e2e86f02bbad6d49d8ac946049a03013c018c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=89=8B=E7=93=9C=E4=B8=80=E5=8D=81=E9=9B=AA?= Date: Fri, 21 Feb 2025 21:12:46 +0800 Subject: [PATCH] napcat.protobuf test --- package.json | 2 + src/common/request.ts | 1 - src/core/external/appid.json | 74 +++++++++++++++++++++++- src/core/packet/client/nativeClient.ts | 16 +++++- src/onebot/index.ts | 7 ++- src/onebot/network/plugin.ts | 4 +- src/plugin/index.ts | 74 ++++++++++++++++++++++-- src/shell/napcat.ts | 80 ++++++++++++++++++++++++++ vite.config.ts | 3 +- 9 files changed, 247 insertions(+), 14 deletions(-) diff --git a/package.json b/package.json index ac86a6c2..d3b3508f 100644 --- a/package.json +++ b/package.json @@ -63,8 +63,10 @@ }, "dependencies": { "@ffmpeg.wasm/core-mt": "^0.13.2", + "@napi-rs/canvas": "^0.1.67", "compressing": "^1.10.1", "express": "^5.0.0", + "napcat.protobuf": "^1.1.2", "piscina": "^4.7.0", "silk-wasm": "^3.6.1", "ws": "^8.18.0" diff --git a/src/common/request.ts b/src/common/request.ts index 6a4e7faa..de33679f 100644 --- a/src/common/request.ts +++ b/src/common/request.ts @@ -109,7 +109,6 @@ export class RequestUtil { req.end(); }); } - // 请求返回都是原始内容 static async HttpGetText(url: string, method: string = 'GET', data?: any, headers: { [key: string]: string } = {}) { return this.HttpGetJson(url, method, data, headers, false, false); diff --git a/src/core/external/appid.json b/src/core/external/appid.json index 563b0039..85a9118e 100644 --- a/src/core/external/appid.json +++ b/src/core/external/appid.json @@ -1,4 +1,76 @@ { + "3.1.2-13107": { + "appid": 537146866, + "qua": "V1_LNX_NQ_3.1.2-13107_RDM_B" + }, + "3.2.10-25765": { + "appid": 537234773, + "qua": "V1_LNX_NQ_3.2.10_25765_GW_B" + }, + "3.2.12-26702": { + "appid": 537237950, + "qua": "V1_LNX_NQ_3.2.12_26702_GW_B" + }, + "3.2.12-26740": { + "appid": 537237950, + "qua": "V1_LNX_NQ_3.2.12_26740_GW_B" + }, + "3.2.12-26909": { + "appid": 537237923, + "qua": "V1_LNX_NQ_3.2.12_26909_GW_B" + }, + "3.2.12-27187": { + "appid": 537240645, + "qua": "V1_LNX_NQ_3.2.12_27187_GW_B" + }, + "3.2.12-27206": { + "appid": 537240645, + "qua": "V1_LNX_NQ_3.2.12_27206_GW_B" + }, + "3.2.12-27254": { + "appid": 537240795, + "qua": "V1_LNX_NQ_3.2.12_27254_GW_B" + }, + "9.9.11-24815": { + "appid": 537226656, + "qua": "V1_WIN_NQ_9.9.11_24815_GW_B" + }, + "9.9.12-25493": { + "appid": 537231759, + "qua": "V1_WIN_NQ_9.9.12_25493_GW_B" + }, + "9.9.12-25765": { + "appid": 537234702, + "qua": "V1_WIN_NQ_9.9.12_25765_GW_B" + }, + "9.9.12-26299": { + "appid": 537234826, + "qua": "V1_WIN_NQ_9.9.12_26299_GW_B" + }, + "9.9.12-26339": { + "appid": 537234826, + "qua": "V1_WIN_NQ_9.9.12_26339_GW_B" + }, + "9.9.12-26466": { + "appid": 537234826, + "qua": "V1_WIN_NQ_9.9.12_26466_GW_B" + }, + "9.9.15-26702": { + "appid": 537237765, + "qua": "V1_WIN_NQ_9.9.15_26702_GW_B" + }, + "9.9.15-26740": { + "appid": 537237765, + "qua": "V1_WIN_NQ_9.9.15_26740_GW_B" + }, + "3.2.12-27556": { + "appid": 537243600, + "qua": "V1_LNX_NQ_3.2.12_27556_GW_B" + }, + "3.2.12-27597": { + "appid": 537243600, + "qua": "V1_LNX_NQ_3.2.12_27597_GW_B" + }, "9.9.15-28060": { "appid": 537246092, "qua": "V1_WIN_NQ_9.9.15_28060_GW_B" @@ -187,4 +259,4 @@ "appid": 537266500, "qua": "V1_WIN_NQ_9.9.17_31363_GW_B" } -} +} \ No newline at end of file diff --git a/src/core/packet/client/nativeClient.ts b/src/core/packet/client/nativeClient.ts index ad3ae995..d031ec11 100644 --- a/src/core/packet/client/nativeClient.ts +++ b/src/core/packet/client/nativeClient.ts @@ -8,7 +8,8 @@ import { LRUCache } from '@/common/lru-cache'; import { LogStack } from '@/core/packet/context/clientContext'; import { NapCoreContext } from '@/core/packet/context/napCoreContext'; import { PacketLogger } from '@/core/packet/context/loggerContext'; - +import { ProtoBufDecode } from 'napcat.protobuf'; +export const MsgData = new LRUCache(5000); // 0 send 1 recv export interface NativePacketExportType { InitHook?: (send: string, recv: string, callback: (type: number, uin: string, cmd: string, seq: number, hex_data: string) => void) => boolean; @@ -55,6 +56,19 @@ export class NativePacketClient extends IPacketClient { // console.log('callback:', callback, trace_id); callback?.({ seq, cmd, hex_data }); } + if (cmd === 'trpc.msg.olpush.OlPushService.MsgPush') { + try { + let msg_info = ProtoBufDecode(Buffer.from(hex_data, 'hex')) as any; + let group_id = (msg_info['1']['1']['8']['1'] as number).toString() + let msg_seq = (msg_info['1']['2']['5'] as number).toString() + let msg_id = group_id + '_' + msg_seq; + MsgData.put(msg_id, hex_data); + console.log('add msgid:', msg_id); + } catch (error) { + console.log('error:', error); + } + + } }); this.available = true; } diff --git a/src/onebot/index.ts b/src/onebot/index.ts index 78b25397..f2aec869 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -50,6 +50,7 @@ import { import { OB11Message } from './types'; import { IOB11NetworkAdapter } from '@/onebot/network/adapter'; import { OB11HttpSSEServerAdapter } from './network/http-server-sse'; +import { OB11PluginAdapter } from './network/plugin'; //OneBot实现类 export class NapCatOneBot11Adapter { @@ -113,9 +114,9 @@ export class NapCatOneBot11Adapter { //创建NetWork服务 // 注册Plugin 如果需要基于NapCat进行快速开发 - // this.networkManager.registerAdapter( - // new OB11PluginAdapter('myPlugin', this.core, this,this.actions) - // ); + this.networkManager.registerAdapter( + new OB11PluginAdapter('myPlugin', this.core, this, this.actions) + ); for (const key of ob11Config.network.httpServers) { if (key.enable) { this.networkManager.registerAdapter( diff --git a/src/onebot/network/plugin.ts b/src/onebot/network/plugin.ts index 717276d9..878f569d 100644 --- a/src/onebot/network/plugin.ts +++ b/src/onebot/network/plugin.ts @@ -15,14 +15,14 @@ export class OB11PluginAdapter extends IOB11NetworkAdapter { messagePostFormat: 'array', reportSelfMessage: false, enable: true, - debug: false, + debug: true, }; super(name, config, core, obContext, actions); } onEvent(event: T) { if (event.post_type === 'message') { - plugin_onmessage(this.config.name, this.core, this.obContext, event as OB11Message, this.actions, this).then().catch(); + plugin_onmessage(this.config.name, this.core, this.obContext, event as OB11Message, this.actions, this).then().catch(console.log); } } diff --git a/src/plugin/index.ts b/src/plugin/index.ts index 484a58b5..de4542cd 100644 --- a/src/plugin/index.ts +++ b/src/plugin/index.ts @@ -1,11 +1,75 @@ -import { NapCatOneBot11Adapter, OB11Message } from '@/onebot'; +import { NapCatOneBot11Adapter, OB11Message, OB11MessageDataType } from '@/onebot'; import { NapCatCore } from '@/core'; import { ActionMap } from '@/onebot/action'; import { OB11PluginAdapter } from '@/onebot/network/plugin'; +import { MsgData } from '@/core/packet/client/nativeClient'; +import { ProtoBufDecode } from 'napcat.protobuf'; +import { drawJsonContent } from '@/shell/napcat'; +import appidList from "@/core/external/appid.json"; export const plugin_onmessage = async (adapter: string, _core: NapCatCore, _obCtx: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap, instance: OB11PluginAdapter) => { - if (message.raw_message === 'ping') { - const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter, instance.config); - console.log(ret); + if (typeof message.message === 'string' || !message.raw) return; + if (!message.message.find(e => e.type == 'text' && e.data.text == '#取')) return; + + let reply = message.raw.elements.find(e => e.replyElement)?.replyElement?.replayMsgSeq; + if (!reply) return; + + let msg_id = message.group_id?.toString() + "_" + reply; + let hex_data = MsgData.get(msg_id); + if (!hex_data) { + console.log('未找到' + msg_id); + return; } -}; + + let decodedData: any = ProtoBufDecode(new Uint8Array(Buffer.from(hex_data, 'hex')), (data) => Buffer.from(data).toString('hex')); + let msgList = []; + for (const keyData of decodedData['1']['3']['1']['2']) { + let mdInner = JSON.stringify(keyData, (_key, value) => typeof value === 'bigint' ? value.toString() : value, 2); + msgList.push({ + type: OB11MessageDataType.node, + data: { + content: [ + { + type: OB11MessageDataType.image, + data: { + file: await drawJsonContent(mdInner) + } + } + ] + } + }); + } + + let now_appid = decodedData['1']['1']['4']; + console.log(now_appid); + let versionList = Object.entries(appidList).filter(([_, appidData]) => appidData.appid == now_appid).map(([version, appidData]) => ({ version, appidData })); + + if (versionList.length > 0) { + let msg = `用户应用号: ${now_appid}`; + if (versionList.length > 1) { + versionList.forEach(version => { + msg += `\n可能的客户端版本: ${version.version}\n可能的客户端识别码: ${version.appidData.qua}`; + }); + } else { + msg += `\n客户端版本: ${versionList[0]?.version}\n客户端识别码: ${versionList[0]?.appidData.qua}`; + } + + msgList.push({ + type: OB11MessageDataType.node, + data: { + content: [ + { + type: OB11MessageDataType.image, + data: { + file: await drawJsonContent(msg) + } + } + ] + } + }); + } + await action.get('send_group_msg')?.handle({ + group_id: String(message.group_id), + message: msgList as any + }, adapter, instance.config); +}; \ No newline at end of file diff --git a/src/shell/napcat.ts b/src/shell/napcat.ts index 7b300cb0..7d4f3b4f 100644 --- a/src/shell/napcat.ts +++ b/src/shell/napcat.ts @@ -1,2 +1,82 @@ import { NCoreInitShell } from './base'; +import { createCanvas, GlobalFonts, loadImage } from '@napi-rs/canvas'; +GlobalFonts.registerFromPath('F:\\fonts\\JetBrainsMono.ttf', 'JetBrains Mono'); +GlobalFonts.registerFromPath('F:\\fonts\\AaCute.ttf', 'Aa偷吃可爱长大的'); + +export async function drawJsonContent(jsonContent: string) { + const lines = jsonContent.split('\n'); + + const padding = 40; + const lineHeight = 30; + const canvas = createCanvas(1, 1); + const ctx = canvas.getContext('2d'); + + let maxLineWidth = 0; + for (const line of lines) { + let lineWidth = 0; + for (const char of line) { + const isChinese = /[\u4e00-\u9fa5]/.test(char); + ctx.font = isChinese ? '20px "Aa偷吃可爱长大的"' : '20px "JetBrains Mono"'; + lineWidth += ctx.measureText(char).width; + } + if (lineWidth > maxLineWidth) { + maxLineWidth = lineWidth; + } + } + + const width = maxLineWidth + padding * 2; + const height = lines.length * lineHeight + padding * 2; + + const finalCanvas = createCanvas(width, height); + const finalCtx = finalCanvas.getContext('2d'); + + const backgroundImage = await loadImage('F:\\BVideo\\Dev\\post.jpg'); + const pattern = finalCtx.createPattern(backgroundImage, 'repeat'); + finalCtx.fillStyle = pattern; + finalCtx.fillRect(0, 0, width, height); + + finalCtx.filter = 'blur(5px)'; + finalCtx.drawImage(finalCanvas, 0, 0); + + finalCtx.filter = 'none'; + const cardWidth = width - padding; + const cardHeight = height - padding; + const cardX = padding / 2; + const cardY = padding / 2; + const radius = 20; + + finalCtx.fillStyle = 'rgba(255, 255, 255, 0.8)'; + finalCtx.beginPath(); + finalCtx.moveTo(cardX + radius, cardY); + finalCtx.lineTo(cardX + cardWidth - radius, cardY); + finalCtx.quadraticCurveTo(cardX + cardWidth, cardY, cardX + cardWidth, cardY + radius); + finalCtx.lineTo(cardX + cardWidth, cardY + cardHeight - radius); + finalCtx.quadraticCurveTo(cardX + cardWidth, cardY + cardHeight, cardX + cardWidth - radius, cardY + cardHeight); + finalCtx.lineTo(cardX + radius, cardY + cardHeight); + finalCtx.quadraticCurveTo(cardX, cardY + cardHeight, cardX, cardY + cardHeight - radius); + finalCtx.lineTo(cardX, cardY + radius); + finalCtx.quadraticCurveTo(cardX, cardY, cardX + radius, cardY); + finalCtx.closePath(); + finalCtx.fill(); + + // 绘制 JSON 内容 + finalCtx.fillStyle = 'black'; + let textY = cardY + 40; + + for (const line of lines) { + let x = cardX + 20; + for (const char of line) { + const isChinese = /[\u4e00-\u9fa5]/.test(char); + finalCtx.font = isChinese ? '20px "Aa偷吃可爱长大的"' : '20px "JetBrains Mono"'; + finalCtx.fillText(char, x, textY); + x += finalCtx.measureText(char).width; + } + textY += 30; + } + + // 保存图像 + const buffer = finalCanvas.toBuffer('image/png'); + return "base64://" + buffer.toString('base64'); +} + NCoreInitShell(); \ No newline at end of file diff --git a/vite.config.ts b/vite.config.ts index 9ff471cf..6b7f0d41 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -9,7 +9,8 @@ const external = [ 'ws', 'express', '@ffmpeg.wasm/core-mt', - 'piscina' + 'piscina', + '@napi-rs/canvas' ]; const nodeModules = [...builtinModules, builtinModules.map((m) => `node:${m}`)].flat();