fix: 进一步重构

This commit is contained in:
手瓜一十雪 2025-01-21 20:40:52 +08:00
parent f5db96187b
commit 4b53e9a895
14 changed files with 166 additions and 320 deletions

View File

@ -2,6 +2,7 @@ import { ActionName, BaseCheckResult } from './router';
import Ajv, { ErrorObject, ValidateFunction } from 'ajv'; import Ajv, { ErrorObject, ValidateFunction } from 'ajv';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
import { NapCatOneBot11Adapter, OB11Return } from '@/onebot'; import { NapCatOneBot11Adapter, OB11Return } from '@/onebot';
import { NetworkAdapterConfig } from '../config/config';
export class OB11Response { export class OB11Response {
private static createResponse<T>(data: T, status: string, retcode: number, message: string = '', echo: any = null): OB11Return<T> { private static createResponse<T>(data: T, status: string, retcode: number, message: string = '', echo: any = null): OB11Return<T> {
@ -55,13 +56,13 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
return { valid: true }; return { valid: true };
} }
public async handle(payload: PayloadType, adaptername: string): Promise<OB11Return<ReturnDataType | null>> { public async handle(payload: PayloadType, adaptername: string, config: NetworkAdapterConfig): Promise<OB11Return<ReturnDataType | null>> {
const result = await this.check(payload); const result = await this.check(payload);
if (!result.valid) { if (!result.valid) {
return OB11Response.error(result.message, 400); return OB11Response.error(result.message, 400);
} }
try { try {
const resData = await this._handle(payload, adaptername); const resData = await this._handle(payload, adaptername, config);
return OB11Response.ok(resData); return OB11Response.ok(resData);
} catch (e: any) { } catch (e: any) {
this.core.context.logger.logError('发生错误', e); this.core.context.logger.logError('发生错误', e);
@ -69,13 +70,13 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
} }
} }
public async websocketHandle(payload: PayloadType, echo: any, adaptername: string): Promise<OB11Return<ReturnDataType | null>> { public async websocketHandle(payload: PayloadType, echo: any, adaptername: string, config: NetworkAdapterConfig): Promise<OB11Return<ReturnDataType | null>> {
const result = await this.check(payload); const result = await this.check(payload);
if (!result.valid) { if (!result.valid) {
return OB11Response.error(result.message, 1400, echo); return OB11Response.error(result.message, 1400, echo);
} }
try { try {
const resData = await this._handle(payload, adaptername); const resData = await this._handle(payload, adaptername, config);
return OB11Response.ok(resData, echo); return OB11Response.ok(resData, echo);
} catch (e: any) { } catch (e: any) {
this.core.context.logger.logError('发生错误', e); this.core.context.logger.logError('发生错误', e);
@ -83,5 +84,5 @@ export abstract class OneBotAction<PayloadType, ReturnDataType> {
} }
} }
abstract _handle(payload: PayloadType, adaptername: string): Promise<ReturnDataType>; abstract _handle(payload: PayloadType, adaptername: string, config: NetworkAdapterConfig): Promise<ReturnDataType>;
} }

View File

@ -3,8 +3,9 @@ import { OB11Message } from '@/onebot';
import { ActionName } from '@/onebot/action/router'; import { ActionName } from '@/onebot/action/router';
import { ChatType } from '@/core/types'; import { ChatType } from '@/core/types';
import { MessageUnique } from '@/common/message-unique'; import { MessageUnique } from '@/common/message-unique';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox'; import { Static, Type } from '@sinclair/typebox';
import { NetworkAdapterConfig } from '@/onebot/config/config';
interface Response { interface Response {
messages: OB11Message[]; messages: OB11Message[];
@ -23,7 +24,7 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
actionName = ActionName.GetFriendMsgHistory; actionName = ActionName.GetFriendMsgHistory;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload, adapter: string): Promise<Response> { async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig): Promise<Response> {
//处理参数 //处理参数
const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString()); const uid = await this.core.apis.UserApi.getUidByUinV2(payload.user_id.toString());
@ -42,10 +43,9 @@ export default class GetFriendMsgHistory extends OneBotAction<Payload, Response>
await Promise.all(msgList.map(async msg => { await Promise.all(msgList.map(async msg => {
msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId); msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
})); }));
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
//烘焙消息 //烘焙消息
const ob11MsgList = (await Promise.all( const ob11MsgList = (await Promise.all(
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array'))) msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat)))
).filter(msg => msg !== undefined); ).filter(msg => msg !== undefined);
return { 'messages': ob11MsgList }; return { 'messages': ob11MsgList };
} }

View File

@ -3,8 +3,8 @@ import { OB11Message } from '@/onebot';
import { ActionName } from '@/onebot/action/router'; import { ActionName } from '@/onebot/action/router';
import { ChatType, Peer } from '@/core/types'; import { ChatType, Peer } from '@/core/types';
import { MessageUnique } from '@/common/message-unique'; import { MessageUnique } from '@/common/message-unique';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox'; import { Static, Type } from '@sinclair/typebox';
import { NetworkAdapterConfig } from '@/onebot/config/config';
interface Response { interface Response {
messages: OB11Message[]; messages: OB11Message[];
@ -25,7 +25,7 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Re
actionName = ActionName.GoCQHTTP_GetGroupMsgHistory; actionName = ActionName.GoCQHTTP_GetGroupMsgHistory;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload, adapter: string): Promise<Response> { async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig): Promise<Response> {
//处理参数 //处理参数
const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder; const isReverseOrder = typeof payload.reverseOrder === 'string' ? payload.reverseOrder === 'true' : !!payload.reverseOrder;
const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() }; const peer: Peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: payload.group_id.toString() };
@ -41,11 +41,9 @@ export default class GoCQHTTPGetGroupMsgHistory extends OneBotAction<Payload, Re
await Promise.all(msgList.map(async msg => { await Promise.all(msgList.map(async msg => {
msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId); msg.id = MessageUnique.createUniqueMsgId({ guildId: '', chatType: msg.chatType, peerUid: msg.peerUid }, msg.msgId);
})); }));
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
//烘焙消息 //烘焙消息
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
const ob11MsgList = (await Promise.all( const ob11MsgList = (await Promise.all(
msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, msgFormat))) msgList.map(msg => this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat)))
).filter(msg => msg !== undefined); ).filter(msg => msg !== undefined);
return { 'messages': ob11MsgList }; return { 'messages': ob11MsgList };
} }

View File

@ -3,8 +3,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router'; import { ActionName } from '@/onebot/action/router';
import { MessageUnique } from '@/common/message-unique'; import { MessageUnique } from '@/common/message-unique';
import crypto from 'crypto'; import crypto from 'crypto';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox'; import { Static, Type } from '@sinclair/typebox';
import { NetworkAdapterConfig } from '@/onebot/config/config';
const SchemaData = Type.Object({ const SchemaData = Type.Object({
group_id: Type.Union([Type.Number(), Type.String()]), group_id: Type.Union([Type.Number(), Type.String()]),
@ -27,9 +27,7 @@ export class GetGroupEssence extends OneBotAction<Payload, any> {
}; };
} }
async _handle(payload: Payload, adapter: string) { async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig) {
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
const msglist = (await this.core.apis.WebApi.getGroupEssenceMsgAll(payload.group_id.toString())).flatMap((e) => e.data.msg_list); const msglist = (await this.core.apis.WebApi.getGroupEssenceMsgAll(payload.group_id.toString())).flatMap((e) => e.data.msg_list);
if (!msglist) { if (!msglist) {
throw new Error('获取失败'); throw new Error('获取失败');
@ -50,7 +48,7 @@ export class GetGroupEssence extends OneBotAction<Payload, any> {
operator_nick: msg.add_digest_nick, operator_nick: msg.add_digest_nick,
message_id: message_id, message_id: message_id,
operator_time: msg.add_digest_time, operator_time: msg.add_digest_time,
content: (await this.obContext.apis.MsgApi.parseMessage(rawMessage, msgFormat))?.message content: (await this.obContext.apis.MsgApi.parseMessage(rawMessage, config.messagePostFormat))?.message
}; };
} }
const msgTempData = JSON.stringify({ const msgTempData = JSON.stringify({

View File

@ -3,8 +3,8 @@ import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router'; import { ActionName } from '@/onebot/action/router';
import { MessageUnique } from '@/common/message-unique'; import { MessageUnique } from '@/common/message-unique';
import { RawMessage } from '@/core'; import { RawMessage } from '@/core';
import { AdapterConfigWrap } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox'; import { Static, Type } from '@sinclair/typebox';
import { NetworkAdapterConfig } from '@/onebot/config/config';
export type ReturnDataType = OB11Message export type ReturnDataType = OB11Message
@ -18,10 +18,8 @@ class GetMsg extends OneBotAction<Payload, OB11Message> {
actionName = ActionName.GetMsg; actionName = ActionName.GetMsg;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload, adapter: string) { async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig) {
// log("history msg ids", Object.keys(msgHistory)); // log("history msg ids", Object.keys(msgHistory));
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
if (!payload.message_id) { if (!payload.message_id) {
throw Error('参数message_id不能为空'); throw Error('参数message_id不能为空');
} }
@ -38,7 +36,7 @@ class GetMsg extends OneBotAction<Payload, OB11Message> {
} else { } else {
msg = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgIdWithPeer?.MsgId || payload.message_id.toString()])).msgList[0]; msg = (await this.core.apis.MsgApi.getMsgsByMsgId(peer, [msgIdWithPeer?.MsgId || payload.message_id.toString()])).msgList[0];
} }
const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg, msgFormat); const retMsg = await this.obContext.apis.MsgApi.parseMessage(msg, config.messagePostFormat);
if (!retMsg) throw Error('消息为空'); if (!retMsg) throw Error('消息为空');
try { try {
retMsg.message_id = MessageUnique.createUniqueMsgId(peer, msg.msgId)!; retMsg.message_id = MessageUnique.createUniqueMsgId(peer, msg.msgId)!;

View File

@ -1,7 +1,7 @@
import { OneBotAction } from '@/onebot/action/OneBotAction'; import { OneBotAction } from '@/onebot/action/OneBotAction';
import { ActionName } from '@/onebot/action/router'; import { ActionName } from '@/onebot/action/router';
import { AdapterConfigWrap } from '@/onebot/config/config'; import { NetworkAdapterConfig } from '@/onebot/config/config';
import { Static, Type } from '@sinclair/typebox'; import { Static, Type } from '@sinclair/typebox';
const SchemaData = Type.Object({ const SchemaData = Type.Object({
@ -14,16 +14,14 @@ export default class GetRecentContact extends OneBotAction<Payload, any> {
actionName = ActionName.GetRecentContact; actionName = ActionName.GetRecentContact;
payloadSchema = SchemaData; payloadSchema = SchemaData;
async _handle(payload: Payload, adapter: string) { async _handle(payload: Payload, adapter: string, config: NetworkAdapterConfig) {
const ret = await this.core.apis.UserApi.getRecentContactListSnapShot(+payload.count); const ret = await this.core.apis.UserApi.getRecentContactListSnapShot(+payload.count);
const network = Object.values(this.obContext.configLoader.configData.network) as Array<AdapterConfigWrap>;
//烘焙消息 //烘焙消息
const msgFormat = network.flat().find(e => e.name === adapter)?.messagePostFormat ?? 'array';
return await Promise.all(ret.info.changedList.map(async (t) => { return await Promise.all(ret.info.changedList.map(async (t) => {
const FastMsg = await this.core.apis.MsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]); const FastMsg = await this.core.apis.MsgApi.getMsgsByMsgId({ chatType: t.chatType, peerUid: t.peerUid }, [t.msgId]);
if (FastMsg.msgList.length > 0) { if (FastMsg.msgList.length > 0) {
//扩展ret.info.changedList //扩展ret.info.changedList
const lastestMsg = await this.obContext.apis.MsgApi.parseMessage(FastMsg.msgList[0], msgFormat); const lastestMsg = await this.obContext.apis.MsgApi.parseMessage(FastMsg.msgList[0], config.messagePostFormat);
return { return {
lastestMsg: lastestMsg, lastestMsg: lastestMsg,
peerUin: t.peerUin, peerUin: t.peerUin,

View File

@ -906,16 +906,16 @@ export class OneBotMsgApi {
const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => { const calculateTotalSize = async (elements: SendMessageElement[]): Promise<number> => {
const sizePromises = elements.map(async element => { const sizePromises = elements.map(async element => {
switch (element.elementType) { switch (element.elementType) {
case ElementType.PTT: case ElementType.PTT:
return (await fsPromise.stat(element.pttElement.filePath)).size; return (await fsPromise.stat(element.pttElement.filePath)).size;
case ElementType.FILE: case ElementType.FILE:
return (await fsPromise.stat(element.fileElement.filePath)).size; return (await fsPromise.stat(element.fileElement.filePath)).size;
case ElementType.VIDEO: case ElementType.VIDEO:
return (await fsPromise.stat(element.videoElement.filePath)).size; return (await fsPromise.stat(element.videoElement.filePath)).size;
case ElementType.PIC: case ElementType.PIC:
return (await fsPromise.stat(element.picElement.sourcePath)).size; return (await fsPromise.stat(element.picElement.sourcePath)).size;
default: default:
return 0; return 0;
} }
}); });
const sizes = await Promise.all(sizePromises); const sizes = await Promise.all(sizePromises);
@ -1008,14 +1008,14 @@ export class OneBotMsgApi {
} }
groupChangDecreseType2String(type: number): GroupDecreaseSubType { groupChangDecreseType2String(type: number): GroupDecreaseSubType {
switch (type) { switch (type) {
case 130: case 130:
return 'leave'; return 'leave';
case 131: case 131:
return 'kick'; return 'kick';
case 3: case 3:
return 'kick_me'; return 'kick_me';
default: default:
return 'kick'; return 'kick';
} }
} }

View File

@ -1,255 +1,109 @@
interface v1Config { import { Type, Static } from '@sinclair/typebox';
http: { import Ajv from 'ajv';
enable: boolean;
host: string;
port: number;
secret: string;
enableHeart: boolean;
enablePost: boolean;
postUrls: string[];
};
ws: {
enable: boolean;
host: string;
port: number;
};
reverseWs: {
enable: boolean;
urls: string[];
};
debug: boolean;
heartInterval: number;
messagePostFormat: string;
enableLocalFile2Url: boolean;
musicSignUrl: string;
reportSelfMessage: boolean;
token: string;
}
export interface AdapterConfigInner {
name: string;
enable: boolean;
} const ajv = new Ajv({ useDefaults: true });
export type AdapterConfigWrap = AdapterConfigInner & Partial<NetworkConfigAdapter>;
export interface AdapterConfig extends AdapterConfigInner { const HttpServerConfigSchema = Type.Object({
[key: string]: any; name: Type.String({ default: 'http-server' }),
} enable: Type.Boolean({ default: false }),
port: Type.Number({ default: 3000 }),
const createDefaultAdapterConfig = <T extends AdapterConfig>(config: T): T => config; host: Type.String({ default: '0.0.0.0' }),
enableCors: Type.Boolean({ default: true }),
export interface PluginConfig extends AdapterConfig { enableWebsocket: Type.Boolean({ default: true }),
name: string; messagePostFormat: Type.String({ default: 'array' }),
enable: boolean; token: Type.String({ default: '' }),
messagePostFormat: string; debug: Type.Boolean({ default: false })
reportSelfMessage: boolean;
debug: boolean;
}
export const httpServerDefaultConfigs = createDefaultAdapterConfig({
name: 'http-server',
enable: false as boolean,
port: 3000,
host: '0.0.0.0',
enableCors: true,
enableWebsocket: true,
messagePostFormat: 'array',
token: '',
debug: false,
});
export type HttpServerConfig = typeof httpServerDefaultConfigs;
export const httpSseServerDefaultConfigs = createDefaultAdapterConfig({
...httpServerDefaultConfigs,
name: 'http-sse-server',
reportSelfMessage: false,
});
export type HttpSseServerConfig = typeof httpSseServerDefaultConfigs;
export const httpClientDefaultConfigs = createDefaultAdapterConfig({
name: 'http-client',
enable: false as boolean,
url: 'http://localhost:8080',
messagePostFormat: 'array',
reportSelfMessage: false,
token: '',
debug: false,
});
export type HttpClientConfig = typeof httpClientDefaultConfigs;
export const websocketServerDefaultConfigs = createDefaultAdapterConfig({
name: 'websocket-server',
enable: false as boolean,
host: '0.0.0.0',
port: 3001,
messagePostFormat: 'array',
reportSelfMessage: false,
token: '',
enableForcePushEvent: true,
debug: false,
heartInterval: 30000,
});
export type WebsocketServerConfig = typeof websocketServerDefaultConfigs;
export const websocketClientDefaultConfigs = createDefaultAdapterConfig({
name: 'websocket-client',
enable: false as boolean,
url: 'ws://localhost:8082',
messagePostFormat: 'array',
reportSelfMessage: false,
reconnectInterval: 5000,
token: '',
debug: false,
heartInterval: 30000,
});
export type WebsocketClientConfig = typeof websocketClientDefaultConfigs;
export interface NetworkConfig {
httpServers: Array<HttpServerConfig>;
httpSseServers: Array<HttpSseServerConfig>;
httpClients: Array<HttpClientConfig>;
websocketServers: Array<WebsocketServerConfig>;
websocketClients: Array<WebsocketClientConfig>;
}
export function mergeConfigs<T extends AdapterConfig>(defaultConfig: T, userConfig: Partial<T>): T {
return { ...defaultConfig, ...userConfig };
}
export interface OneBotConfig {
network: NetworkConfig; // 网络配置
musicSignUrl: string; // 音乐签名地址
enableLocalFile2Url: boolean;
parseMultMsg: boolean;
}
const createDefaultConfig = <T>(config: T): T => config;
export const defaultOneBotConfigs = createDefaultConfig<OneBotConfig>({
network: {
httpServers: [],
httpSseServers: [],
httpClients: [],
websocketServers: [],
websocketClients: [],
},
musicSignUrl: '',
enableLocalFile2Url: false,
parseMultMsg: true
}); });
export const mergeNetworkDefaultConfig = { const HttpSseServerConfigSchema = Type.Object({
httpSseServers: httpSseServerDefaultConfigs, name: Type.String({ default: 'http-sse-server' }),
httpServers: httpServerDefaultConfigs, enable: Type.Boolean({ default: false }),
httpClients: httpClientDefaultConfigs, port: Type.Number({ default: 3000 }),
websocketServers: websocketServerDefaultConfigs, host: Type.String({ default: '0.0.0.0' }),
websocketClients: websocketClientDefaultConfigs, enableCors: Type.Boolean({ default: true }),
} as const; enableWebsocket: Type.Boolean({ default: true }),
messagePostFormat: Type.String({ default: 'array' }),
token: Type.String({ default: '' }),
debug: Type.Boolean({ default: false }),
reportSelfMessage: Type.Boolean({ default: false })
});
export type NetworkConfigAdapter = HttpServerConfig | HttpSseServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig | PluginConfig; const HttpClientConfigSchema = Type.Object({
type NetworkConfigKeys = keyof typeof mergeNetworkDefaultConfig; name: Type.String({ default: 'http-client' }),
enable: Type.Boolean({ default: false }),
url: Type.String({ default: 'http://localhost:8080' }),
messagePostFormat: Type.String({ default: 'array' }),
reportSelfMessage: Type.Boolean({ default: false }),
token: Type.String({ default: '' }),
debug: Type.Boolean({ default: false })
});
export function mergeOneBotConfigs( const WebsocketServerConfigSchema = Type.Object({
userConfig: Partial<OneBotConfig>, name: Type.String({ default: 'websocket-server' }),
defaultConfig: OneBotConfig = defaultOneBotConfigs enable: Type.Boolean({ default: false }),
): OneBotConfig { host: Type.String({ default: '0.0.0.0' }),
const mergedConfig = { ...defaultConfig }; port: Type.Number({ default: 3001 }),
messagePostFormat: Type.String({ default: 'array' }),
reportSelfMessage: Type.Boolean({ default: false }),
token: Type.String({ default: '' }),
enableForcePushEvent: Type.Boolean({ default: true }),
debug: Type.Boolean({ default: false }),
heartInterval: Type.Number({ default: 30000 })
});
if (userConfig.network) { const WebsocketClientConfigSchema = Type.Object({
mergedConfig.network = { ...defaultConfig.network }; name: Type.String({ default: 'websocket-client' }),
for (const key in userConfig.network) { enable: Type.Boolean({ default: false }),
const userNetworkConfig = userConfig.network[key as keyof NetworkConfig]; url: Type.String({ default: 'ws://localhost:8082' }),
const defaultNetworkConfig = mergeNetworkDefaultConfig[key as NetworkConfigKeys]; messagePostFormat: Type.String({ default: 'array' }),
if (Array.isArray(userNetworkConfig)) { reportSelfMessage: Type.Boolean({ default: false }),
mergedConfig.network[key as keyof NetworkConfig] = userNetworkConfig.map<any>((e) => reconnectInterval: Type.Number({ default: 5000 }),
mergeConfigs(defaultNetworkConfig, e) token: Type.String({ default: '' }),
); debug: Type.Boolean({ default: false }),
} heartInterval: Type.Number({ default: 30000 })
} });
const PluginConfigSchema = Type.Object({
name: Type.String({ default: 'plugin' }),
enable: Type.Boolean({ default: false }),
messagePostFormat: Type.String({ default: 'array' }),
reportSelfMessage: Type.Boolean({ default: false }),
debug: Type.Boolean({ default: false }),
});
const NetworkConfigSchema = Type.Object({
httpServers: Type.Array(HttpServerConfigSchema),
httpSseServers: Type.Array(HttpSseServerConfigSchema),
httpClients: Type.Array(HttpClientConfigSchema),
websocketServers: Type.Array(WebsocketServerConfigSchema),
websocketClients: Type.Array(WebsocketClientConfigSchema),
plugins: Type.Array(PluginConfigSchema)
});
const OneBotConfigSchema = Type.Object({
network: NetworkConfigSchema,
musicSignUrl: Type.String({ default: '' }),
enableLocalFile2Url: Type.Boolean({ default: false }),
parseMultMsg: Type.Boolean({ default: true })
});
export type OneBotConfig = Static<typeof OneBotConfigSchema>;
export type HttpServerConfig = Static<typeof HttpServerConfigSchema>;
export type HttpSseServerConfig = Static<typeof HttpSseServerConfigSchema>;
export type HttpClientConfig = Static<typeof HttpClientConfigSchema>;
export type WebsocketServerConfig = Static<typeof WebsocketServerConfigSchema>;
export type WebsocketClientConfig = Static<typeof WebsocketClientConfigSchema>;
export type PluginConfig = Static<typeof PluginConfigSchema>;
export type NetworkAdapterConfig = HttpServerConfig | HttpSseServerConfig | HttpClientConfig | WebsocketServerConfig | WebsocketClientConfig| PluginConfig;
const validate = ajv.compile(OneBotConfigSchema);
export function loadConfig(config: Partial<OneBotConfig>): OneBotConfig {
const valid = validate(config);
if (!valid) {
throw new Error(ajv.errorsText(validate.errors));
} }
if (userConfig.musicSignUrl !== undefined) { return config as OneBotConfig;
mergedConfig.musicSignUrl = userConfig.musicSignUrl;
}
if (userConfig.enableLocalFile2Url !== undefined) {
mergedConfig.enableLocalFile2Url = userConfig.enableLocalFile2Url;
}
if (userConfig.parseMultMsg !== undefined) {
mergedConfig.parseMultMsg = userConfig.parseMultMsg;
}
return mergedConfig;
}
function checkIsOneBotConfigV1(v1Config: Partial<v1Config>): boolean {
return v1Config.http !== undefined || v1Config.ws !== undefined || v1Config.reverseWs !== undefined;
}
export function migrateOneBotConfigsV1(config: Partial<v1Config>): OneBotConfig {
if (!checkIsOneBotConfigV1(config)) {
return config as OneBotConfig;
}
const mergedConfig = { ...defaultOneBotConfigs };
if (config.http) {
mergedConfig.network.httpServers = [
mergeConfigs(httpServerDefaultConfigs, {
name: 'http-server',
enable: config.http.enable,
port: config.http.port,
host: config.http.host,
token: config.http.secret,
debug: config.debug,
messagePostFormat: config.messagePostFormat,
}),
];
}
if (config.ws) {
mergedConfig.network.websocketServers = [
mergeConfigs(websocketServerDefaultConfigs, {
name: 'websocket-server',
enable: config.ws.enable,
port: config.ws.port,
host: config.ws.host,
token: config.token,
debug: config.debug,
messagePostFormat: config.messagePostFormat,
reportSelfMessage: config.reportSelfMessage,
}),
];
}
if (config.reverseWs) {
mergedConfig.network.websocketClients = config.reverseWs.urls.map((url) =>
mergeConfigs(websocketClientDefaultConfigs, {
name: 'websocket-client-' + config.reverseWs?.urls.indexOf(url).toString(),
enable: config.reverseWs?.enable,
url: url,
token: config.token,
debug: config.debug,
messagePostFormat: config.messagePostFormat,
reportSelfMessage: config.reportSelfMessage,
})
);
}
if (config.heartInterval) {
mergedConfig.network.websocketServers[0].heartInterval = config.heartInterval;
}
if (config.musicSignUrl) {
mergedConfig.musicSignUrl = config.musicSignUrl;
}
if (config.enableLocalFile2Url) {
mergedConfig.enableLocalFile2Url = config.enableLocalFile2Url;
}
return mergedConfig;
}
export function getConfigBoolKey(
configs: Array<NetworkConfigAdapter>,
prediction: (config: NetworkConfigAdapter) => boolean
): { positive: Array<string>, negative: Array<string> } {
const result: { positive: string[], negative: string[] } = { positive: [], negative: [] };
configs.forEach(config => {
if (prediction(config)) {
result.positive.push(config.name);
} else {
result.negative.push(config.name);
}
});
return result;
} }

View File

@ -44,10 +44,8 @@ import { LRUCache } from '@/common/lru-cache';
import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener'; import { NodeIKernelRecentContactListener } from '@/core/listeners/NodeIKernelRecentContactListener';
import { BotOfflineEvent } from './event/notice/BotOfflineEvent'; import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
import { import {
AdapterConfigWrap, NetworkAdapterConfig,
mergeOneBotConfigs, loadConfig,
migrateOneBotConfigsV1,
NetworkConfigAdapter,
OneBotConfig, OneBotConfig,
} from './config/config'; } from './config/config';
import { OB11Message } from './types'; import { OB11Message } from './types';
@ -71,8 +69,8 @@ export class NapCatOneBot11Adapter {
this.core = core; this.core = core;
this.context = context; this.context = context;
this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath); this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath);
this.configLoader.save(migrateOneBotConfigsV1(this.configLoader.configData)); this.configLoader.save(this.configLoader.configData);
this.configLoader.save(mergeOneBotConfigs(this.configLoader.configData)); this.configLoader.save(loadConfig(this.configLoader.configData));
this.apis = { this.apis = {
GroupApi: new OneBotGroupApi(this, core), GroupApi: new OneBotGroupApi(this, core),
UserApi: new OneBotUserApi(this, core), UserApi: new OneBotUserApi(this, core),
@ -181,7 +179,7 @@ export class NapCatOneBot11Adapter {
WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => { WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
const prev = this.configLoader.configData; const prev = this.configLoader.configData;
// 保证默认配置 // 保证默认配置
newConfig = mergeOneBotConfigs(newConfig); newConfig = loadConfig(newConfig);
this.configLoader.save(newConfig); this.configLoader.save(newConfig);
//this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); //this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`);
@ -215,9 +213,9 @@ export class NapCatOneBot11Adapter {
await this.handleConfigChange(prev.network.websocketClients, now.network.websocketClients, OB11ActiveWebSocketAdapter); await this.handleConfigChange(prev.network.websocketClients, now.network.websocketClients, OB11ActiveWebSocketAdapter);
} }
private async handleConfigChange<CT extends NetworkConfigAdapter>( private async handleConfigChange<CT extends NetworkAdapterConfig>(
prevConfig: NetworkConfigAdapter[], prevConfig: NetworkAdapterConfig[],
nowConfig: NetworkConfigAdapter[], nowConfig: NetworkAdapterConfig[],
adapterClass: new ( adapterClass: new (
...args: ConstructorParameters<typeof IOB11NetworkAdapter<CT>> ...args: ConstructorParameters<typeof IOB11NetworkAdapter<CT>>
) => IOB11NetworkAdapter<CT> ) => IOB11NetworkAdapter<CT>
@ -479,7 +477,7 @@ export class NapCatOneBot11Adapter {
]); ]);
} }
private async handleMsg(message: RawMessage, network: Array<AdapterConfigWrap>) { private async handleMsg(message: RawMessage, network: Array<NetworkAdapterConfig>) {
// 过滤无效消息 // 过滤无效消息
if (message.msgType === NTMsgType.KMSGTYPENULL) { if (message.msgType === NTMsgType.KMSGTYPENULL) {
return; return;
@ -508,7 +506,7 @@ export class NapCatOneBot11Adapter {
ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin; ob11Msg.arrayMsg.user_id.toString() == this.core.selfInfo.uin;
} }
private createMsgMap(network: Array<AdapterConfigWrap>, ob11Msg: any, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> { private createMsgMap(network: Array<NetworkAdapterConfig>, ob11Msg: any, isSelfMsg: boolean, message: RawMessage): Map<string, OB11Message> {
const msgMap: Map<string, OB11Message> = new Map(); const msgMap: Map<string, OB11Message> = new Map();
network.filter(e => e.enable).forEach(e => { network.filter(e => e.enable).forEach(e => {
if (isSelfMsg || message.chatType !== ChatType.KCHATTYPEGROUP) { if (isSelfMsg || message.chatType !== ChatType.KCHATTYPEGROUP) {
@ -525,7 +523,7 @@ export class NapCatOneBot11Adapter {
return msgMap; return msgMap;
} }
private handleDebugNetwork(network: Array<AdapterConfigWrap>, msgMap: Map<string, OB11Message>, message: RawMessage) { private handleDebugNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, message: RawMessage) {
const debugNetwork = network.filter(e => e.enable && e.debug); const debugNetwork = network.filter(e => e.enable && e.debug);
if (debugNetwork.length > 0) { if (debugNetwork.length > 0) {
debugNetwork.forEach(adapter => { debugNetwork.forEach(adapter => {
@ -539,7 +537,7 @@ export class NapCatOneBot11Adapter {
} }
} }
private handleNotReportSelfNetwork(network: Array<AdapterConfigWrap>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) { private handleNotReportSelfNetwork(network: Array<NetworkAdapterConfig>, msgMap: Map<string, OB11Message>, isSelfMsg: boolean) {
if (isSelfMsg) { if (isSelfMsg) {
const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e))); const notReportSelfNetwork = network.filter(e => e.enable && (('reportSelfMessage' in e && !e.reportSelfMessage) || !('reportSelfMessage' in e)));
notReportSelfNetwork.forEach(adapter => { notReportSelfNetwork.forEach(adapter => {

View File

@ -1,11 +1,11 @@
import { NetworkConfigAdapter } from "@/onebot/config/config"; import { NetworkAdapterConfig } from "@/onebot/config/config";
import { LogWrapper } from "@/common/log"; import { LogWrapper } from "@/common/log";
import { NapCatCore } from "@/core"; import { NapCatCore } from "@/core";
import { NapCatOneBot11Adapter } from "@/onebot"; import { NapCatOneBot11Adapter } from "@/onebot";
import { ActionMap } from "@/onebot/action"; import { ActionMap } from "@/onebot/action";
import { OB11EmitEventContent, OB11NetworkReloadType } from "@/onebot/network/index"; import { OB11EmitEventContent, OB11NetworkReloadType } from "@/onebot/network/index";
export abstract class IOB11NetworkAdapter<CT extends NetworkConfigAdapter> { export abstract class IOB11NetworkAdapter<CT extends NetworkAdapterConfig> {
name: string; name: string;
isEnable: boolean = false; isEnable: boolean = false;
config: CT; config: CT;

View File

@ -1,6 +1,6 @@
import { OneBotEvent } from '@/onebot/event/OneBotEvent'; import { OneBotEvent } from '@/onebot/event/OneBotEvent';
import { OB11Message } from '@/onebot'; import { OB11Message } from '@/onebot';
import { NetworkConfigAdapter } from '@/onebot/config/config'; import { NetworkAdapterConfig } from '@/onebot/config/config';
import { IOB11NetworkAdapter } from "@/onebot/network/adapter"; import { IOB11NetworkAdapter } from "@/onebot/network/adapter";
export type OB11EmitEventContent = OneBotEvent | OB11Message; export type OB11EmitEventContent = OneBotEvent | OB11Message;
@ -13,7 +13,7 @@ export enum OB11NetworkReloadType {
} }
export class OB11NetworkManager { export class OB11NetworkManager {
adapters: Map<string, IOB11NetworkAdapter<NetworkConfigAdapter>> = new Map(); adapters: Map<string, IOB11NetworkAdapter<NetworkAdapterConfig>> = new Map();
async openAllAdapters() { async openAllAdapters() {
return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.open())); return Promise.all(Array.from(this.adapters.values()).map(adapter => adapter.open()));
@ -49,22 +49,22 @@ export class OB11NetworkManager {
})); }));
} }
registerAdapter<CT extends NetworkConfigAdapter>(adapter: IOB11NetworkAdapter<CT>) { registerAdapter<CT extends NetworkAdapterConfig>(adapter: IOB11NetworkAdapter<CT>) {
this.adapters.set(adapter.name, adapter); this.adapters.set(adapter.name, adapter);
} }
async registerAdapterAndOpen<CT extends NetworkConfigAdapter>(adapter: IOB11NetworkAdapter<CT>) { async registerAdapterAndOpen<CT extends NetworkAdapterConfig>(adapter: IOB11NetworkAdapter<CT>) {
this.registerAdapter(adapter); this.registerAdapter(adapter);
await adapter.open(); await adapter.open();
} }
async closeSomeAdapters<CT extends NetworkConfigAdapter>(adaptersToClose: IOB11NetworkAdapter<CT>[]) { async closeSomeAdapters<CT extends NetworkAdapterConfig>(adaptersToClose: IOB11NetworkAdapter<CT>[]) {
for (const adapter of adaptersToClose) { for (const adapter of adaptersToClose) {
this.adapters.delete(adapter.name); this.adapters.delete(adapter.name);
await adapter.close(); await adapter.close();
} }
} }
async closeSomeAdaterWhenOpen<CT extends NetworkConfigAdapter>(adaptersToClose: IOB11NetworkAdapter<CT>[]) { async closeSomeAdaterWhenOpen<CT extends NetworkAdapterConfig>(adaptersToClose: IOB11NetworkAdapter<CT>[]) {
for (const adapter of adaptersToClose) { for (const adapter of adaptersToClose) {
this.adapters.delete(adapter.name); this.adapters.delete(adapter.name);
if (adapter.isEnable) { if (adapter.isEnable) {
@ -77,7 +77,7 @@ export class OB11NetworkManager {
return this.adapters.get(name); return this.adapters.get(name);
} }
async closeAdapterByPredicate(closeFilter: (adapter: IOB11NetworkAdapter<NetworkConfigAdapter>) => boolean) { async closeAdapterByPredicate(closeFilter: (adapter: IOB11NetworkAdapter<NetworkAdapterConfig>) => boolean) {
const adaptersToClose = Array.from(this.adapters.values()).filter(closeFilter); const adaptersToClose = Array.from(this.adapters.values()).filter(closeFilter);
await this.closeSomeAdapters(adaptersToClose); await this.closeSomeAdapters(adaptersToClose);
} }

View File

@ -22,7 +22,7 @@ export class OB11PluginAdapter extends IOB11NetworkAdapter<PluginConfig> {
onEvent<T extends OB11EmitEventContent>(event: T) { onEvent<T extends OB11EmitEventContent>(event: T) {
if (event.post_type === 'message') { if (event.post_type === 'message') {
plugin_onmessage(this.config.name, this.core, this.obContext, event as OB11Message,this.actions).then().catch(); plugin_onmessage(this.config.name, this.core, this.obContext, event as OB11Message, this.actions, this).then().catch();
} }
} }

View File

@ -1,10 +1,11 @@
import { NapCatOneBot11Adapter, OB11Message } from "@/onebot"; import { NapCatOneBot11Adapter, OB11Message } from "@/onebot";
import { NapCatCore } from "@/core"; import { NapCatCore } from "@/core";
import { ActionMap } from "@/onebot/action"; import { ActionMap } from "@/onebot/action";
import { OB11PluginAdapter } from "@/onebot/network/plugin";
export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCtx: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap) => { export const plugin_onmessage = async (adapter: string, core: NapCatCore, obCtx: NapCatOneBot11Adapter, message: OB11Message, action: ActionMap, instance: OB11PluginAdapter) => {
if (message.raw_message === 'ping') { if (message.raw_message === 'ping') {
const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter); const ret = await action.get('send_group_msg')?.handle({ group_id: String(message.group_id), message: 'pong' }, adapter, instance.config);
console.log(ret); console.log(ret);
} }
}; };

View File

@ -1,6 +1,6 @@
declare global { declare global {
namespace globalThis { namespace globalThis {
var LiteLoader: Symbol; const LiteLoader: symbol;
} }
} }
export {} export {};