feat: msg push

This commit is contained in:
手瓜一十雪 2024-11-14 20:18:19 +08:00
parent a0a50755d3
commit 4487db4e0a
15 changed files with 345 additions and 245 deletions

View File

@ -8,12 +8,12 @@ export abstract class ConfigBase<T> {
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<T> {
}
}
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'));

View File

@ -37,13 +37,13 @@ abstract class BaseAction<PayloadType, ReturnDataType> {
};
}
public async handle(payload: PayloadType): Promise<OB11Return<ReturnDataType | null>> {
public async handle(payload: PayloadType, adaptername: string): Promise<OB11Return<ReturnDataType | null>> {
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<PayloadType, ReturnDataType> {
}
}
public async websocketHandle(payload: PayloadType, echo: any): Promise<OB11Return<ReturnDataType | null>> {
public async websocketHandle(payload: PayloadType, echo: any, adaptername: string): Promise<OB11Return<ReturnDataType | null>> {
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<PayloadType, ReturnDataType> {
}
}
abstract _handle(payload: PayloadType): PromiseLike<ReturnDataType>;
abstract _handle(payload: PayloadType, adaptername: string): PromiseLike<ReturnDataType>;
}
export default BaseAction;

View File

@ -72,7 +72,7 @@ export class GoCQHTTPGetForwardMsgAction extends BaseAction<Payload, any> {
}
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('找不到相关的聊天记录');
}

View File

@ -26,7 +26,7 @@ export default class GetFriendMsgHistory extends BaseAction<Payload, Response> {
actionName = ActionName.GetFriendMsgHistory;
payloadSchema = SchemaData;
async _handle(payload: Payload): Promise<Response> {
async _handle(payload: Payload, adapter: string): Promise<Response> {
//处理参数
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<Payload, Response> {
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<typeof this.obContext.configLoader.configData.network[keyof typeof this.obContext.configLoader.configData.network]>;
//烘焙消息
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 };
}

View File

@ -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<MessageElement[keyof RawToOb11Converters], null | undefined>,
msg: RawMessage,
elementWrapper: MessageElement,
) => PromiseLike<OB11MessageData | null>;
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) => (<PromiseFulfilledResult<OB11MessageData>>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,

View File

@ -1,6 +1,6 @@
export interface AdapterConfig {
name: string;
enabled: boolean;
enable: boolean;
[key: string]: any;
}
@ -8,8 +8,8 @@ const createDefaultAdapterConfig = <T extends AdapterConfig>(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<T extends AdapterConfig>(defaultConfig: T, userConf
export interface OnebotConfig {
network: NetworkConfig;//网络配置
musicSignUrl: string;//音乐签名地址
enableLocalFile2Url: boolean
}
const createDefaultConfig = <T>(config: T): T => config;
@ -82,7 +83,8 @@ export const defaultOnebotConfig = createDefaultConfig<OnebotConfig>({
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;
}
}

View File

@ -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<OB11Config> {
export class OB11ConfigLoader extends ConfigBase<OnebotConfig> {
constructor(core: NapCatCore, configPath: string) {
super('onebot11', core, configPath);
super('onebot11', core, configPath, false);
}
}

View File

@ -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": ""
}

View File

@ -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<string>(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<string>(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<string>(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<string>(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<T>(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<typeof this.configLoader.configData.network[keyof typeof this.configLoader.configData.network]>;
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<string, OB11Message> = 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 => {

View File

@ -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,

View File

@ -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<any>(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<any>({ ...retdata });
}
}

View File

@ -6,6 +6,7 @@ export type OB11EmitEventContent = OB11BaseEvent | OB11Message;
export interface IOB11NetworkAdapter {
actions?: ActionMap;
name: string;
onEvent<T extends OB11EmitEventContent>(event: T): void;
@ -15,19 +16,34 @@ export interface IOB11NetworkAdapter {
}
export class OB11NetworkManager {
adapters: IOB11NetworkAdapter[] = [];
adapters: Map<string, IOB11NetworkAdapter> = 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<string,OB11EmitEventContent>){
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';

View File

@ -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));

View File

@ -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<any>(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<any>({ ...retdata }, wsClient);
}
}

View File

@ -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) => {