From 4487db4e0a57514f5d46bd2e6df1bc13cfdf62e8 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: Thu, 14 Nov 2024 20:18:19 +0800 Subject: [PATCH] feat: msg push --- src/common/config-base.ts | 10 +- src/onebot/action/BaseAction.ts | 10 +- src/onebot/action/go-cqhttp/GetForwardMsg.ts | 2 +- .../action/go-cqhttp/GetFriendMsgHistory.ts | 5 +- src/onebot/api/msg.ts | 108 +++++- src/onebot/config/config.ts | 20 +- src/onebot/config/index.ts | 8 +- src/onebot/config/onebot11.json | 31 -- src/onebot/index.ts | 336 +++++++++--------- src/onebot/network/active-http.ts | 1 + src/onebot/network/active-websocket.ts | 3 +- src/onebot/network/index.ts | 48 ++- src/onebot/network/passive-http.ts | 3 +- src/onebot/network/passive-websocket.ts | 3 +- vite.config.ts | 2 - 15 files changed, 345 insertions(+), 245 deletions(-) delete mode 100644 src/onebot/config/onebot11.json diff --git a/src/common/config-base.ts b/src/common/config-base.ts index 8070c79b..4593c78c 100644 --- a/src/common/config-base.ts +++ b/src/common/config-base.ts @@ -8,12 +8,12 @@ export abstract class ConfigBase { configPath: string; configData: T = {} as T; - protected constructor(name: string, core: NapCatCore, configPath: string) { + protected constructor(name: string, core: NapCatCore, configPath: string, copy_default: boolean = true) { this.name = name; this.core = core; this.configPath = configPath; fs.mkdirSync(this.configPath, { recursive: true }); - this.read(); + this.read(copy_default); } protected getKeys(): string[] | null { @@ -32,16 +32,18 @@ export abstract class ConfigBase { } } - read(): T { + read(copy_default: boolean = true): T { const logger = this.core.context.logger; const configPath = this.getConfigPath(this.core.selfInfo.uin); - if (!fs.existsSync(configPath)) { + if (!fs.existsSync(configPath) && copy_default) { try { fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8')); logger.log(`[Core] [Config] 配置文件创建成功!\n`); } catch (e: any) { logger.logError.bind(logger)(`[Core] [Config] 创建配置文件时发生错误:`, e.message); } + } else if (!fs.existsSync(configPath) && !copy_default) { + fs.writeFileSync(configPath, '{}'); } try { this.configData = JSON.parse(fs.readFileSync(configPath, 'utf-8')); diff --git a/src/onebot/action/BaseAction.ts b/src/onebot/action/BaseAction.ts index f374d02a..a19f155e 100644 --- a/src/onebot/action/BaseAction.ts +++ b/src/onebot/action/BaseAction.ts @@ -37,13 +37,13 @@ abstract class BaseAction { }; } - public async handle(payload: PayloadType): Promise> { + public async handle(payload: PayloadType, adaptername: string): Promise> { const result = await this.check(payload); if (!result.valid) { return OB11Response.error(result.message, 400); } try { - const resData = await this._handle(payload); + const resData = await this._handle(payload, adaptername); return OB11Response.ok(resData); } catch (e: any) { this.core.context.logger.logError.bind(this.core.context.logger)('发生错误', e); @@ -51,13 +51,13 @@ abstract class BaseAction { } } - public async websocketHandle(payload: PayloadType, echo: any): Promise> { + public async websocketHandle(payload: PayloadType, echo: any, adaptername: string): Promise> { const result = await this.check(payload); if (!result.valid) { return OB11Response.error(result.message, 1400, echo); } try { - const resData = await this._handle(payload); + const resData = await this._handle(payload, adaptername); return OB11Response.ok(resData, echo); } catch (e: any) { this.core.context.logger.logError.bind(this.core.context.logger)('发生错误', e); @@ -65,7 +65,7 @@ abstract class BaseAction { } } - abstract _handle(payload: PayloadType): PromiseLike; + abstract _handle(payload: PayloadType, adaptername: string): PromiseLike; } export default BaseAction; diff --git a/src/onebot/action/go-cqhttp/GetForwardMsg.ts b/src/onebot/action/go-cqhttp/GetForwardMsg.ts index b640b2d8..7db98ba1 100644 --- a/src/onebot/action/go-cqhttp/GetForwardMsg.ts +++ b/src/onebot/action/go-cqhttp/GetForwardMsg.ts @@ -72,7 +72,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction { } const singleMsg = data.msgList[0]; - const resMsg = await this.obContext.apis.MsgApi.parseMessage(singleMsg, 'array');//强制array 以便处理 + const resMsg = (await this.obContext.apis.MsgApi.parseMessageV2(singleMsg))?.arrayMsg;//强制array 以便处理 if (!(resMsg?.message?.[0] as OB11MessageForward)?.data?.content) { throw new Error('找不到相关的聊天记录'); } diff --git a/src/onebot/action/go-cqhttp/GetFriendMsgHistory.ts b/src/onebot/action/go-cqhttp/GetFriendMsgHistory.ts index b8ce16d6..7efd553a 100644 --- a/src/onebot/action/go-cqhttp/GetFriendMsgHistory.ts +++ b/src/onebot/action/go-cqhttp/GetFriendMsgHistory.ts @@ -26,7 +26,7 @@ export default class GetFriendMsgHistory extends BaseAction { actionName = ActionName.GetFriendMsgHistory; payloadSchema = SchemaData; - async _handle(payload: Payload): Promise { + async _handle(payload: Payload, adapter: string): Promise { //处理参数 const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); const MsgCount = +(payload.count ?? 20); @@ -45,9 +45,10 @@ export default class GetFriendMsgHistory extends BaseAction { await Promise.all(msgList.map(async msg => { msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId); })); + let network = Object.values(this.obContext.configLoader.configData.network) as Array; //烘焙消息 const ob11MsgList = (await Promise.all( - msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg))) + msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array'))) ).filter(msg => msg !== undefined); return { 'messages': ob11MsgList }; } diff --git a/src/onebot/api/msg.ts b/src/onebot/api/msg.ts index 6058f508..56d7d6b6 100644 --- a/src/onebot/api/msg.ts +++ b/src/onebot/api/msg.ts @@ -368,7 +368,7 @@ export class OneBotMsgApi { multiMsgItem.parentMsgPeer = parentMsgPeer; multiMsgItem.parentMsgIdList = msg.parentMsgIdList; multiMsgItem.id = MessageUnique.createUniqueMsgId(parentMsgPeer, multiMsgItem.msgId); //该ID仅用查看 无法调用 - return await this.parseMessage(multiMsgItem); + return await this.parseMessage(multiMsgItem, 'array'); }, ))).filter(item => item !== undefined), }, @@ -693,7 +693,7 @@ export class OneBotMsgApi { async parseMessage( msg: RawMessage, - messagePostFormat: string = this.obContext.configLoader.configData.messagePostFormat, + messagePostFormat: string, ) { if (msg.senderUin == '0' || msg.senderUin == '') return; if (msg.peerUin == '0' || msg.peerUin == '') return; @@ -796,6 +796,110 @@ export class OneBotMsgApi { return resMsg; } + async parseMessageV2( + msg: RawMessage, + ) { + if (msg.senderUin == '0' || msg.senderUin == '') return; + if (msg.peerUin == '0' || msg.peerUin == '') return; + //跳过空消息 + const resMsg: OB11Message = { + self_id: parseInt(this.core.selfInfo.uin), + user_id: parseInt(msg.senderUin), + time: parseInt(msg.msgTime) || Date.now(), + message_id: msg.id!, + message_seq: msg.id!, + real_id: msg.id!, + message_type: msg.chatType == ChatType.KCHATTYPEGROUP ? 'group' : 'private', + sender: { + user_id: +(msg.senderUin ?? 0), + nickname: msg.sendNickName, + card: msg.sendMemberName ?? '', + }, + raw_message: '', + font: 14, + sub_type: 'friend', + message: [], + message_format: 'array', + post_type: this.core.selfInfo.uin == msg.senderUin ? EventType.MESSAGE_SENT : EventType.MESSAGE, + }; + if (this.core.selfInfo.uin == msg.senderUin) { + resMsg.message_sent_type = 'self'; + } + if (msg.chatType == ChatType.KCHATTYPEGROUP) { + resMsg.sub_type = 'normal'; // 这里go-cqhttp是group,而onebot11标准是normal, 蛋疼 + resMsg.group_id = parseInt(msg.peerUin); + let member = await this.core.apis.GroupApi.getGroupMember(msg.peerUin, msg.senderUin); + if (!member) member = await this.core.apis.GroupApi.getGroupMember(msg.peerUin, msg.senderUin); + if (member) { + resMsg.sender.role = OB11Entities.groupMemberRole(member.role); + resMsg.sender.nickname = member.nick; + } + } else if (msg.chatType == ChatType.KCHATTYPEC2C) { + resMsg.sub_type = 'friend'; + resMsg.sender.nickname = (await this.core.apis.UserApi.getUserDetailInfo(msg.senderUid)).nick; + } else if (msg.chatType == ChatType.KCHATTYPETEMPC2CFROMGROUP) { + resMsg.sub_type = 'group'; + const ret = await this.core.apis.MsgApi.getTempChatInfo(ChatType.KCHATTYPETEMPC2CFROMGROUP, msg.senderUid); + if (ret.result === 0) { + const member = await this.core.apis.GroupApi.getGroupMember(msg.peerUin, msg.senderUin); + resMsg.group_id = parseInt(ret.tmpChatInfo!.groupCode); + resMsg.sender.nickname = member?.nick ?? member?.cardName ?? '临时会话'; + resMsg.temp_source = resMsg.group_id; + } else { + resMsg.group_id = 284840486; //兜底数据 + resMsg.temp_source = resMsg.group_id; + resMsg.sender.nickname = '临时会话'; + } + } + + // 处理消息段 + const msgSegments = await Promise.allSettled(msg.elements.map( + async (element) => { + for (const key in element) { + if (keyCanBeParsed(key, this.rawToOb11Converters) && element[key]) { + const converters = this.rawToOb11Converters[key] as ( + element: Exclude, + msg: RawMessage, + elementWrapper: MessageElement, + ) => PromiseLike; + const parsedElement = await converters?.( + element[key], + msg, + element, + ); + // 对于 face 类型的消息,检查是否存在 + if (key === 'faceElement' && !parsedElement) { + return null; // 如果没有找到对应的表情,返回 null + } + + return parsedElement; + } + } + }, + )); + + // 过滤掉无效的消息段 + const validSegments = msgSegments.filter(entry => { + if (entry.status === 'fulfilled') { + return !!entry.value; + } else { + this.core.context.logger.logError.bind(this.core.context.logger)('消息段解析失败', entry.reason); + return false; + } + }).map((entry) => (>entry).value).filter(value => value != null); + + const msgAsCQCode = validSegments.map(msg => encodeCQCode(msg)).join('').trim(); + resMsg.message = validSegments; + resMsg.raw_message = msgAsCQCode; + let stringMsg = structuredClone(resMsg); + stringMsg = await this.importArrayTostringMsg(stringMsg); + return { stringMsg: stringMsg, arrayMsg: resMsg }; + } + async importArrayTostringMsg(msg: OB11Message) { + msg.message_format = 'string'; + msg.message = msg.raw_message; + return msg; + } async createSendElements( messageData: OB11MessageData[], peer: Peer, diff --git a/src/onebot/config/config.ts b/src/onebot/config/config.ts index ce2fe955..66dae188 100644 --- a/src/onebot/config/config.ts +++ b/src/onebot/config/config.ts @@ -1,6 +1,6 @@ export interface AdapterConfig { name: string; - enabled: boolean; + enable: boolean; [key: string]: any; } @@ -8,8 +8,8 @@ const createDefaultAdapterConfig = (config: T): T => co const httpServerDefaultConfigs = createDefaultAdapterConfig({ name: 'http-server', - enabled: false, - port: '3000', + enable: false, + port: 3000, host: '0.0.0.0', enableCors: true, enableWebsocket: true, @@ -22,7 +22,7 @@ export type HttpServerConfig = typeof httpServerDefaultConfigs; const httpClientDefaultConfigs = createDefaultAdapterConfig({ name: 'http-client', - enabled: false, + enable: false, url: 'http://localhost:8080', messagePostFormat: 'array', reportSelfMessage: false, @@ -33,9 +33,9 @@ export type HttpClientConfig = typeof httpClientDefaultConfigs; const websocketServerDefaultConfigs = createDefaultAdapterConfig({ name: 'websocket-server', - enabled: false, + enable: false, host: '0.0.0.0', - port: '3002', + port: 3002, messagePostFormat: 'array', reportSelfMessage: false, token: '', @@ -47,7 +47,7 @@ export type WebsocketServerConfig = typeof websocketServerDefaultConfigs; const websocketClientDefaultConfigs = createDefaultAdapterConfig({ name: 'websocket-client', - enabled: false, + enable: false, url: 'ws://localhost:8082', messagePostFormat: 'array', reportSelfMessage: false, @@ -71,6 +71,7 @@ export function mergeConfigs(defaultConfig: T, userConf export interface OnebotConfig { network: NetworkConfig;//网络配置 musicSignUrl: string;//音乐签名地址 + enableLocalFile2Url: boolean } const createDefaultConfig = (config: T): T => config; @@ -82,7 +83,8 @@ export const defaultOnebotConfig = createDefaultConfig({ websocketServers: [], websocketClients: [], }, - musicSignUrl: "" + musicSignUrl: "", + enableLocalFile2Url: false }) export const mergeNetworkDefaultConfig = { httpServers: httpServerDefaultConfigs, @@ -110,4 +112,4 @@ export function mergeOnebotConfigs(defaultConfig: OnebotConfig, userConfig: Part mergedConfig.musicSignUrl = userConfig.musicSignUrl; } return mergedConfig; -} \ No newline at end of file +} diff --git a/src/onebot/config/index.ts b/src/onebot/config/index.ts index 7d517095..c378cf0b 100644 --- a/src/onebot/config/index.ts +++ b/src/onebot/config/index.ts @@ -1,11 +1,9 @@ import { ConfigBase } from '@/common/config-base'; -import ob11DefaultConfig from './onebot11.json'; import { NapCatCore } from '@/core'; +import { OnebotConfig } from './config'; -export type OB11Config = typeof ob11DefaultConfig; - -export class OB11ConfigLoader extends ConfigBase { +export class OB11ConfigLoader extends ConfigBase { constructor(core: NapCatCore, configPath: string) { - super('onebot11', core, configPath); + super('onebot11', core, configPath, false); } } diff --git a/src/onebot/config/onebot11.json b/src/onebot/config/onebot11.json deleted file mode 100644 index 8ee5a368..00000000 --- a/src/onebot/config/onebot11.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "http": { - "enable": false, - "host": "", - "port": 3000, - "secret": "", - "enableHeart": false, - "enablePost": false, - "postUrls": [] - }, - "ws": { - "enable": false, - "host": "", - "port": 3001 - }, - "reverseWs": { - "enable": false, - "urls": [] - }, - "GroupLocalTime": { - "Record": false, - "RecordList": [] - }, - "debug": false, - "heartInterval": 30000, - "messagePostFormat": "array", - "enableLocalFile2Url": true, - "musicSignUrl": "", - "reportSelfMessage": false, - "token": "" -} diff --git a/src/onebot/index.ts b/src/onebot/index.ts index f496d2e1..930f0335 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -14,7 +14,7 @@ import { RawMessage, SendStatusType, } from '@/core'; -import { OB11Config, OB11ConfigLoader } from '@/onebot/config'; +import { OB11ConfigLoader } from '@/onebot/config'; import { OB11ActiveHttpAdapter, OB11ActiveWebSocketAdapter, @@ -45,6 +45,8 @@ import { OB11GroupRecallNoticeEvent } from '@/onebot/event/notice/OB11GroupRecal import { LRUCache } from '@/common/lru-cache'; import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener'; import { BotOfflineEvent } from './event/notice/BotOfflineEvent'; +import { defaultOnebotConfig, mergeOnebotConfigs, OnebotConfig } from './config/config'; +import { OB11Message } from './types'; //OneBot实现类 export class NapCatOneBot11Adapter { @@ -61,7 +63,8 @@ export class NapCatOneBot11Adapter { constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) { this.core = core; this.context = context; - this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath); + this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath,); + this.configLoader.save(mergeOnebotConfigs(defaultOnebotConfig, this.configLoader.configData)); this.apis = { GroupApi: new OneBotGroupApi(this, core), UserApi: new OneBotUserApi(this, core), @@ -72,65 +75,77 @@ export class NapCatOneBot11Adapter { this.actions = createActionMap(this, core); this.networkManager = new OB11NetworkManager(); } - + async creatOneBotLog(ob11Config: OnebotConfig) { + let log = `[network] 配置加载\n`; + for (const key of ob11Config.network.httpServers) { + log += `HTTP服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`; + } + for (const key of ob11Config.network.httpClients) { + log += `HTTP上报服务: ${key.url}, : ${key.enable ? '已启动' : '未启动'}\n`; + } + for (const key of ob11Config.network.websocketServers) { + log += `WebSocket服务: ${key.host}:${key.port}, : ${key.enable ? '已启动' : '未启动'}\n`; + } + for (const key of ob11Config.network.websocketClients) { + log += `WebSocket反向服务: ${key.url}, : ${key.enable ? '已启动' : '未启动'}\n`; + } + return log; + } async InitOneBot() { const selfInfo = this.core.selfInfo; const ob11Config = this.configLoader.configData; - const serviceInfo = ` - HTTP服务 ${ob11Config.http.enable ? '已启动' : '未启动'}, ${ob11Config.http.host}:${ob11Config.http.port} - HTTP上报服务 ${ob11Config.http.enablePost ? '已启动' : '未启动'}, 上报地址: ${ob11Config.http.postUrls} - WebSocket服务 ${ob11Config.ws.enable ? '已启动' : '未启动'}, ${ob11Config.ws.host}:${ob11Config.ws.port} - WebSocket反向服务 ${ob11Config.reverseWs.enable ? '已启动' : '未启动'}, 反向地址: ${ob11Config.reverseWs.urls}`; - this.core.apis.UserApi.getUserDetailInfo(selfInfo.uid).then(user => { selfInfo.nick = user.nick; this.context.logger.setLogSelfInfo(selfInfo); }).catch(this.context.logger.logError.bind(this.context.logger)); + + let serviceInfo = await this.creatOneBotLog(ob11Config); this.context.logger.log(`[Notice] [OneBot11] ${serviceInfo}`); - //创建NetWork服务 - if (ob11Config.http.enable) { - this.networkManager.registerAdapter(new OB11PassiveHttpAdapter( - ob11Config.http.port, ob11Config.token, this.core, this.actions, - )); + // //创建NetWork服务 + for (const key of ob11Config.network.httpServers) { + if (key.enable) { + this.networkManager.registerAdapter(new OB11PassiveHttpAdapter( + key.name, key.port, key.token, this.core, this.actions, + )); + } } - if (ob11Config.http.enablePost) { - ob11Config.http.postUrls.forEach(url => { + for (const key of ob11Config.network.httpClients) { + if (key.enable) { this.networkManager.registerAdapter(new OB11ActiveHttpAdapter( - url, ob11Config.http.secret, this.core, this, + key.name, key.url, key.token, this.core, this, )); - }); + } } - if (ob11Config.ws.enable) { - const OBPassiveWebSocketAdapter = new OB11PassiveWebSocketAdapter( - ob11Config.ws.host, ob11Config.ws.port, ob11Config.heartInterval, ob11Config.token, this.core, this.actions, - ); - this.networkManager.registerAdapter(OBPassiveWebSocketAdapter); + for (const key of ob11Config.network.websocketServers) { + if (key.enable) { + this.networkManager.registerAdapter(new OB11PassiveWebSocketAdapter( + key.name, key.host, key.port, key.heartInterval, key.token, this.core, this.actions, + )); + } } - if (ob11Config.reverseWs.enable) { - ob11Config.reverseWs.urls.forEach(url => { + for (const key of ob11Config.network.websocketClients) { + if (key.enable) { this.networkManager.registerAdapter(new OB11ActiveWebSocketAdapter( - url, 5000, ob11Config.heartInterval, ob11Config.token, this.core, this.actions, + key.name, key.url, 5000, key.heartInterval, key.token, this.core, this.actions, )); - }); + } } - await this.networkManager.openAllAdapters(); this.initMsgListener(); this.initBuddyListener(); this.initGroupListener(); - //this.initRecentContactListener(); await WebUiDataRuntime.setQQLoginUin(selfInfo.uin.toString()); await WebUiDataRuntime.setQQLoginStatus(true); - await WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig: OB11Config) => { - const prev = this.configLoader.configData; - this.configLoader.save(newConfig); - this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); - await this.reloadNetwork(prev, newConfig); - }); + // await WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig: OB11Config) => { + // const prev = this.configLoader.configData; + // this.configLoader.save(newConfig); + // this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); + // await this.reloadNetwork(prev, newConfig); + // }); } initRecentContactListener() { @@ -144,88 +159,88 @@ export class NapCatOneBot11Adapter { }; } - private async reloadNetwork(prev: OB11Config, now: OB11Config) { - const serviceInfo = ` - HTTP服务 ${now.http.enable ? '已启动' : '未启动'}, ${now.http.host}:${now.http.port} - HTTP上报服务 ${now.http.enablePost ? '已启动' : '未启动'}, 上报地址: ${now.http.postUrls} - WebSocket服务 ${now.ws.enable ? '已启动' : '未启动'}, ${now.ws.host}:${now.ws.port} - WebSocket反向服务 ${now.reverseWs.enable ? '已启动' : '未启动'}, 反向地址: ${now.reverseWs.urls}`; - this.context.logger.log(`[Notice] [OneBot11] 热重载 ${serviceInfo}`); + // private async reloadNetwork(prev: OB11Config, now: OB11Config) { + // const serviceInfo = ` + // HTTP服务 ${now.http.enable ? '已启动' : '未启动'}, ${now.http.host}:${now.http.port} + // HTTP上报服务 ${now.http.enablePost ? '已启动' : '未启动'}, 上报地址: ${now.http.postUrls} + // WebSocket服务 ${now.ws.enable ? '已启动' : '未启动'}, ${now.ws.host}:${now.ws.port} + // WebSocket反向服务 ${now.reverseWs.enable ? '已启动' : '未启动'}, 反向地址: ${now.reverseWs.urls}`; + // this.context.logger.log(`[Notice] [OneBot11] 热重载 ${serviceInfo}`); - // check difference in passive http (Http) - if (prev.http.enable !== now.http.enable) { - if (now.http.enable) { - await this.networkManager.registerAdapterAndOpen(new OB11PassiveHttpAdapter( - now.http.port, now.token, this.core, this.actions, - )); - } else { - await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11PassiveHttpAdapter); - } - } + // // check difference in passive http (Http) + // if (prev.http.enable !== now.http.enable) { + // if (now.http.enable) { + // await this.networkManager.registerAdapterAndOpen(new OB11PassiveHttpAdapter( + // now.http.port, now.token, this.core, this.actions, + // )); + // } else { + // await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11PassiveHttpAdapter); + // } + // } - // check difference in active http (HttpPost) - if (prev.http.enablePost !== now.http.enablePost) { - if (now.http.enablePost) { - now.http.postUrls.forEach(url => { - this.networkManager.registerAdapterAndOpen(new OB11ActiveHttpAdapter( - url, now.http.secret, this.core, this, - )); - }); - } else { - await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11ActiveHttpAdapter); - } - } else if (now.http.enablePost) { - const { added, removed } = this.findDifference(prev.http.postUrls, now.http.postUrls); - await this.networkManager.closeAdapterByPredicate( - adapter => adapter instanceof OB11ActiveHttpAdapter && removed.includes(adapter.url), - ); - for (const url of added) { - await this.networkManager.registerAdapterAndOpen(new OB11ActiveHttpAdapter( - url, now.http.secret, this.core, this, - )); - } - } + // // check difference in active http (HttpPost) + // if (prev.http.enablePost !== now.http.enablePost) { + // if (now.http.enablePost) { + // now.http.postUrls.forEach(url => { + // this.networkManager.registerAdapterAndOpen(new OB11ActiveHttpAdapter( + // url, now.http.secret, this.core, this, + // )); + // }); + // } else { + // await this.networkManager.closeAdapterByPredicate(adapter => adapter instanceof OB11ActiveHttpAdapter); + // } + // } else if (now.http.enablePost) { + // const { added, removed } = this.findDifference(prev.http.postUrls, now.http.postUrls); + // await this.networkManager.closeAdapterByPredicate( + // adapter => adapter instanceof OB11ActiveHttpAdapter && removed.includes(adapter.url), + // ); + // for (const url of added) { + // await this.networkManager.registerAdapterAndOpen(new OB11ActiveHttpAdapter( + // url, now.http.secret, this.core, this, + // )); + // } + // } - // check difference in passive websocket (Ws) - if (prev.ws.enable !== now.ws.enable) { - if (now.ws.enable) { - await this.networkManager.registerAdapterAndOpen(new OB11PassiveWebSocketAdapter( - now.ws.host, now.ws.port, now.heartInterval, now.token, this.core, this.actions, - )); - } else { - await this.networkManager.closeAdapterByPredicate( - adapter => adapter instanceof OB11PassiveWebSocketAdapter, - ); - } - } + // // check difference in passive websocket (Ws) + // if (prev.ws.enable !== now.ws.enable) { + // if (now.ws.enable) { + // await this.networkManager.registerAdapterAndOpen(new OB11PassiveWebSocketAdapter( + // now.ws.host, now.ws.port, now.heartInterval, now.token, this.core, this.actions, + // )); + // } else { + // await this.networkManager.closeAdapterByPredicate( + // adapter => adapter instanceof OB11PassiveWebSocketAdapter, + // ); + // } + // } - // check difference in active websocket (ReverseWs) - if (prev.reverseWs.enable !== now.reverseWs.enable) { - if (now.reverseWs.enable) { - now.reverseWs.urls.forEach(url => { - this.networkManager.registerAdapterAndOpen(new OB11ActiveWebSocketAdapter( - url, 5000, now.heartInterval, now.token, this.core, this.actions, - )); - }); - } else { - await this.networkManager.closeAdapterByPredicate( - adapter => adapter instanceof OB11ActiveWebSocketAdapter, - ); - } - } else if (now.reverseWs.enable) { - const { added, removed } = this.findDifference(prev.reverseWs.urls, now.reverseWs.urls); - await this.networkManager.closeAdapterByPredicate( - adapter => adapter instanceof OB11ActiveWebSocketAdapter && removed.includes(adapter.url), - ); - for (const url of added) { - await this.networkManager.registerAdapterAndOpen(new OB11ActiveWebSocketAdapter( - url, 5000, now.heartInterval, now.token, this.core, this.actions, - )); - } - } + // // check difference in active websocket (ReverseWs) + // if (prev.reverseWs.enable !== now.reverseWs.enable) { + // if (now.reverseWs.enable) { + // now.reverseWs.urls.forEach(url => { + // this.networkManager.registerAdapterAndOpen(new OB11ActiveWebSocketAdapter( + // url, 5000, now.heartInterval, now.token, this.core, this.actions, + // )); + // }); + // } else { + // await this.networkManager.closeAdapterByPredicate( + // adapter => adapter instanceof OB11ActiveWebSocketAdapter, + // ); + // } + // } else if (now.reverseWs.enable) { + // const { added, removed } = this.findDifference(prev.reverseWs.urls, now.reverseWs.urls); + // await this.networkManager.closeAdapterByPredicate( + // adapter => adapter instanceof OB11ActiveWebSocketAdapter && removed.includes(adapter.url), + // ); + // for (const url of added) { + // await this.networkManager.registerAdapterAndOpen(new OB11ActiveWebSocketAdapter( + // url, 5000, now.heartInterval, now.token, this.core, this.actions, + // )); + // } + // } - } + // } private findDifference(prev: T[], now: T[]): { added: T[], removed: T[] } { const added = now.filter(item => !prev.includes(item)); @@ -285,21 +300,12 @@ export class NapCatOneBot11Adapter { if (msg.sendStatus == SendStatusType.KSEND_STATUS_SUCCESS && msgIdSend.get(msg.msgId) == 0) { msgIdSend.put(msg.msgId, 1); // 完成后再post - this.apis.MsgApi.parseMessage(msg) - .then((ob11Msg) => { - if (!ob11Msg) return; - ob11Msg.target_id = parseInt(msg.peerUin); - if (this.configLoader.configData.reportSelfMessage) { - msg.id = MessageUnique.createUniqueMsgId({ - chatType: msg.chatType, - peerUid: msg.peerUid, - guildId: '', - }, msg.msgId); - this.emitMsg(msg); - } else { - // logOB11Message(this.core, ob11Msg); - } - }); + msg.id = MessageUnique.createUniqueMsgId({ + chatType: msg.chatType, + peerUid: msg.peerUid, + guildId: '', + }, msg.msgId); + this.emitMsg(msg, true); } } }; @@ -491,56 +497,52 @@ export class NapCatOneBot11Adapter { ); } - private async emitMsg(message: RawMessage, parseEvent: boolean = true) { - const { debug, reportSelfMessage, messagePostFormat } = this.configLoader.configData; + private async emitMsg(message: RawMessage, selfMsg: boolean = true) { + let network = Object.values(this.configLoader.configData.network) as Array; this.context.logger.logDebug('收到新消息 RawMessage', message); - this.apis.MsgApi.parseMessage(message, messagePostFormat).then((ob11Msg) => { + this.apis.MsgApi.parseMessageV2(message).then((ob11Msg) => { if (!ob11Msg) return; + const isSelfMsg = ob11Msg.stringMsg.user_id.toString() == this.core.selfInfo.uin || ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin; this.context.logger.logDebug('转化为 OB11Message', ob11Msg); - if (debug) { - ob11Msg.raw = message; - } else if (ob11Msg.message.length === 0) { + let msgMap: Map = new Map(); + let enable_client: string[] = []; + network.flat().filter(e => e.enable).map(e => { + enable_client.push(e.name); + if (e.messagePostFormat == 'string') { + msgMap.set(e.name, structuredClone(ob11Msg.stringMsg)); + } else { + msgMap.set(e.name, structuredClone(ob11Msg.arrayMsg)); + } + if (isSelfMsg) { + ob11Msg.stringMsg.target_id = parseInt(message.peerUin); + ob11Msg.arrayMsg.target_id = parseInt(message.peerUin); + } + }); + + let debug_network = network.flat().filter(e => e.enable && e.debug); + if (debug_network.length > 0) { + for (const adapter of debug_network) { + if (adapter.name) { + const msg = msgMap.get(adapter.name); + if (msg) { + msg.raw = message; + } + + } + + } + } else if (ob11Msg.stringMsg.message.length === 0 || ob11Msg.arrayMsg.message.length == 0) { return; } - const isSelfMsg = ob11Msg.user_id.toString() == this.core.selfInfo.uin; - if (isSelfMsg && !reportSelfMessage) { - return; - } + let notreportSelf_network = network.flat().filter(e => e.enable && !e.reportSelfMessage); if (isSelfMsg) { - ob11Msg.target_id = parseInt(message.peerUin); + for (const adapter of notreportSelf_network) { + msgMap.delete(adapter.name); + } } - // if (ob11Msg.raw_message.startsWith('!set')) { - // this.core.apis.UserApi.getUidByUinV2(ob11Msg.user_id.toString()).then(uid => { - // if(uid){ - // this.core.apis.PacketApi.sendSetSpecialTittlePacket(message.peerUin, uid, '测试'); - // console.log('set', message.peerUin, uid); - // } - // }); - - // } - // if (ob11Msg.raw_message.startsWith('!status')) { - // console.log('status', message.peerUin, message.senderUin); - // let delMsg: string[] = []; - // let peer = { - // peerUid: message.peerUin, - // chatType: 2, - // }; - // this.core.apis.PacketApi.sendStatusPacket(+message.senderUin).then(async e => { - // if (e) { - // const { sendElements } = await this.apis.MsgApi.createSendElements([{ - // type: OB11MessageDataType.text, - // data: { - // text: 'status ' + JSON.stringify(e, null, 2), - // } - // }], peer) - - // this.apis.MsgApi.sendMsgWithOb11UniqueId(peer, sendElements, delMsg) - // } - // }) - // } - this.networkManager.emitEvent(ob11Msg); + this.networkManager.emitEventByNames(msgMap); }).catch(e => this.context.logger.logError.bind(this.context.logger)('constructMessage error: ', e)); this.apis.GroupApi.parseGroupEvent(message).then(groupEvent => { diff --git a/src/onebot/network/active-http.ts b/src/onebot/network/active-http.ts index 26687929..16cec876 100644 --- a/src/onebot/network/active-http.ts +++ b/src/onebot/network/active-http.ts @@ -10,6 +10,7 @@ export class OB11ActiveHttpAdapter implements IOB11NetworkAdapter { isOpen: boolean = false; constructor( + public name: string, public url: string, public secret: string | undefined, public core: NapCatCore, diff --git a/src/onebot/network/active-websocket.ts b/src/onebot/network/active-websocket.ts index 9b33e11e..31c4ed20 100644 --- a/src/onebot/network/active-websocket.ts +++ b/src/onebot/network/active-websocket.ts @@ -15,6 +15,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter { private heartbeatRef: NodeJS.Timeout | null = null; constructor( + public name: string, public url: string, public reconnectIntervalInMillis: number, public heartbeatIntervalInMillis: number, @@ -147,7 +148,7 @@ export class OB11ActiveWebSocketAdapter implements IOB11NetworkAdapter { this.checkStateAndReply(OB11Response.error('不支持的api ' + receiveData.action, 1404, echo)); return; } - const retdata = await action.websocketHandle(receiveData.params, echo ?? ''); + const retdata = await action.websocketHandle(receiveData.params, echo ?? '', this.name); this.checkStateAndReply({ ...retdata }); } } diff --git a/src/onebot/network/index.ts b/src/onebot/network/index.ts index 9d4b16b5..57c0b0eb 100644 --- a/src/onebot/network/index.ts +++ b/src/onebot/network/index.ts @@ -6,6 +6,7 @@ export type OB11EmitEventContent = OB11BaseEvent | OB11Message; export interface IOB11NetworkAdapter { actions?: ActionMap; + name: string; onEvent(event: T): void; @@ -15,19 +16,34 @@ export interface IOB11NetworkAdapter { } export class OB11NetworkManager { - adapters: IOB11NetworkAdapter[] = []; + adapters: Map = new Map(); async openAllAdapters() { - return Promise.all(this.adapters.map(adapter => adapter.open())); + return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.open())); } async emitEvent(event: OB11EmitEventContent) { - //console.log('adapters', this.adapters.length); - return Promise.all(this.adapters.map(adapter => adapter.onEvent(event))); + return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.onEvent(event))); } + async emitEventByName(names: string[], event: OB11EmitEventContent) { + return Promise.all(names.map(name => { + const adapter = this.adapters.get(name); + if (adapter) { + return adapter.onEvent(event); + } + })); + } + async emitEventByNames(map:Map){ + return Promise.all(Array.from(map.entries()).map(([name, event]) => { + const adapter = this.adapters.get(name); + if (adapter) { + return adapter.onEvent(event); + } + })); + } registerAdapter(adapter: IOB11NetworkAdapter) { - this.adapters.push(adapter); + this.adapters.set(adapter.name, adapter); } async registerAdapterAndOpen(adapter: IOB11NetworkAdapter) { @@ -36,24 +52,28 @@ export class OB11NetworkManager { } async closeSomeAdapters(adaptersToClose: IOB11NetworkAdapter[]) { - this.adapters = this.adapters.filter(adapter => !adaptersToClose.includes(adapter)); - await Promise.all(adaptersToClose.map(adapter => adapter.close())); + for (const adapter of adaptersToClose) { + this.adapters.delete(adapter.name); + await adapter.close(); + } + } + + findSomeAdapter(name: string) { + return this.adapters.get(name); } - /** - * Close all adapters that satisfy the predicate. - */ async closeAdapterByPredicate(closeFilter: (adapter: IOB11NetworkAdapter) => boolean) { - await this.closeSomeAdapters(this.adapters.filter(closeFilter)); + const adaptersToClose = Array.from(this.adapters.values()).filter(closeFilter); + await this.closeSomeAdapters(adaptersToClose); } async closeAllAdapters() { - await Promise.all(this.adapters.map(adapter => adapter.close())); - this.adapters = []; + await Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.close())); + this.adapters.clear(); } } export * from './active-http'; export * from './active-websocket'; export * from './passive-http'; -export * from './passive-websocket'; +export * from './passive-websocket'; \ No newline at end of file diff --git a/src/onebot/network/passive-http.ts b/src/onebot/network/passive-http.ts index 2ebaf624..bab26cd8 100644 --- a/src/onebot/network/passive-http.ts +++ b/src/onebot/network/passive-http.ts @@ -12,6 +12,7 @@ export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter { private isOpen: boolean = false; constructor( + public name: string, public port: number, public token: string, public core: NapCatCore, @@ -101,7 +102,7 @@ export class OB11PassiveHttpAdapter implements IOB11NetworkAdapter { const action = this.actions.get(actionName); if (action) { try { - const result = await action.handle(payload); + const result = await action.handle(payload,this.name); return res.json(result); } catch (error: any) { return res.json(OB11Response.error(error?.stack?.toString() || error?.message || 'Error Handle', 200)); diff --git a/src/onebot/network/passive-websocket.ts b/src/onebot/network/passive-websocket.ts index e4a8f597..7edc299a 100644 --- a/src/onebot/network/passive-websocket.ts +++ b/src/onebot/network/passive-websocket.ts @@ -24,6 +24,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter { wsClientWithEvent: WebSocket[] = []; constructor( + public name: string, ip: string, port: number, heartbeatInterval: number, @@ -188,7 +189,7 @@ export class OB11PassiveWebSocketAdapter implements IOB11NetworkAdapter { this.checkStateAndReply(OB11Response.error('不支持的api ' + receiveData.action, 1404, echo), wsClient); return; } - const retdata = await action.websocketHandle(receiveData.params, echo ?? ''); + const retdata = await action.websocketHandle(receiveData.params, echo ?? '', this.name); this.checkStateAndReply({ ...retdata }, wsClient); } } diff --git a/vite.config.ts b/vite.config.ts index 81d5d9c7..7f379421 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -24,7 +24,6 @@ const FrameworkBaseConfigPlugin: PluginOption[] = [ { src: './src/core/external/napcat.json', dest: 'dist/config/' }, { src: './src/native/packet', dest: 'dist/moehoo', flatten: false }, { src: './static/', dest: 'dist/static/', flatten: false }, - { src: './src/onebot/config/onebot11.json', dest: 'dist/config/' }, { src: './src/framework/liteloader.cjs', dest: 'dist' }, { src: './src/framework/napcat.cjs', dest: 'dist' }, { src: './src/framework/preload.cjs', dest: 'dist' }, @@ -41,7 +40,6 @@ const ShellBaseConfigPlugin: PluginOption[] = [ { src: './src/native/packet', dest: 'dist/moehoo', flatten: false }, { src: './static/', dest: 'dist/static/', flatten: false }, { src: './src/core/external/napcat.json', dest: 'dist/config/' }, - { src: './src/onebot/config/onebot11.json', dest: 'dist/config/' }, { src: './package.json', dest: 'dist' }, { src: './launcher/', dest: 'dist', flatten: true }, ...(startScripts.map((startScript) => {