From 11a7f5fade2ce3798469503de8e20e0dea549db2 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: Tue, 4 Feb 2025 18:09:30 +0800 Subject: [PATCH] refactor --- src/common/config-base.ts | 75 ++++++++++++++++++------------------- src/core/helper/config.ts | 20 +++++++--- src/core/index.ts | 4 +- src/onebot/config/config.ts | 2 +- src/onebot/config/index.ts | 5 ++- src/onebot/index.ts | 9 +---- 6 files changed, 60 insertions(+), 55 deletions(-) diff --git a/src/common/config-base.ts b/src/common/config-base.ts index 50274f08..8769f620 100644 --- a/src/common/config-base.ts +++ b/src/common/config-base.ts @@ -2,73 +2,72 @@ import path from 'node:path'; import fs from 'node:fs'; import type { NapCatCore } from '@/core'; import json5 from 'json5'; +import Ajv, { AnySchema, ValidateFunction } from 'ajv'; export abstract class ConfigBase { name: string; core: NapCatCore; configPath: string; configData: T = {} as T; + ajv: Ajv; + validate: ValidateFunction; - protected constructor(name: string, core: NapCatCore, configPath: string, copy_default: boolean = true) { + protected constructor(name: string, core: NapCatCore, configPath: string, ConfigSchema: AnySchema) { this.name = name; this.core = core; this.configPath = configPath; + this.ajv = new Ajv({ useDefaults: true, coerceTypes: true }); + this.validate = this.ajv.compile(ConfigSchema); fs.mkdirSync(this.configPath, { recursive: true }); - this.read(copy_default); + this.read(); } - protected getKeys(): string[] | null { - // 决定 key 在json配置文件中的顺序 - return null; + getConfigPath(pathName?: string): string { + const filename = pathName ? `${this.name}_${pathName}.json` : `${this.name}.json`; + return path.join(this.configPath, filename); } - getConfigPath(pathName: string | undefined): string { - if (!pathName) { - const filename = `${this.name}.json`; - const mainPath = this.core.context.pathWrapper.binaryPath; - return path.join(mainPath, 'config', filename); - } else { - const filename = `${this.name}_${pathName}.json`; - return path.join(this.configPath, filename); - } - } - - read(copy_default: boolean = true): T { - + read(): T { const configPath = this.getConfigPath(this.core.selfInfo.uin); - if (!fs.existsSync(configPath) && copy_default) { - try { - fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8')); - this.core.context.logger.log('[Core] [Config] 配置文件创建成功!\n'); - } catch (e: unknown) { - this.core.context.logger.logError('[Core] [Config] 创建配置文件时发生错误:', (e as Error).message); + const defaultConfigPath = this.getConfigPath(); + if (!fs.existsSync(configPath)) { + if (fs.existsSync(defaultConfigPath)) { + this.configData = this.loadConfig(defaultConfigPath); } - } else if (!fs.existsSync(configPath) && !copy_default) { - fs.writeFileSync(configPath, '{}'); + this.validate(this.configData); + this.save(); + return this.configData; } + return this.loadConfig(configPath); + } + + private loadConfig(configPath: string): T { try { this.configData = json5.parse(fs.readFileSync(configPath, 'utf-8')); this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData); return this.configData; } catch (e: unknown) { - if (e instanceof SyntaxError) { - this.core.context.logger.logError('[Core] [Config] 配置文件格式错误,请检查配置文件:', e.message); - } else { - this.core.context.logger.logError('[Core] [Config] 读取配置文件时发生错误:', (e as Error).message); - } + this.handleError(e, '读取配置文件时发生错误'); return {} as T; } } - - save(newConfigData: T = this.configData) { - const selfInfo = this.core.selfInfo; + save(newConfigData: T = this.configData): void { + const configPath = this.getConfigPath(this.core.selfInfo.uin); + this.validate(newConfigData); this.configData = newConfigData; - const configPath = this.getConfigPath(selfInfo.uin); try { - fs.writeFileSync(configPath, JSON.stringify(newConfigData, this.getKeys(), 2)); + fs.writeFileSync(configPath, JSON.stringify(this.configData, null, 2)); } catch (e: unknown) { - this.core.context.logger.logError(`保存配置文件 ${configPath} 时发生错误:`, (e as Error).message); + this.handleError(e, `保存配置文件 ${configPath} 时发生错误:`); } } -} + + private handleError(e: unknown, message: string): void { + if (e instanceof SyntaxError) { + this.core.context.logger.logError(`[Core] [Config] 操作配置文件格式错误,请检查配置文件:`, e.message); + } else { + this.core.context.logger.logError(`[Core] [Config] ${message}:`, (e as Error).message); + } + } +} \ No newline at end of file diff --git a/src/core/helper/config.ts b/src/core/helper/config.ts index eb9b15e7..22b590d0 100644 --- a/src/core/helper/config.ts +++ b/src/core/helper/config.ts @@ -1,11 +1,21 @@ import { ConfigBase } from '@/common/config-base'; -import napCatDefaultConfig from '@/core/external/napcat.json'; import { NapCatCore } from '@/core'; +import { Type, Static } from '@sinclair/typebox'; +import { AnySchema } from 'ajv'; -export type NapCatConfig = typeof napCatDefaultConfig; +export const NapcatConfigSchema = Type.Object({ + fileLog: Type.Boolean({ default: false }), + consoleLog: Type.Boolean({ default: true }), + fileLogLevel: Type.String({ default: 'debug' }), + consoleLogLevel: Type.String({ default: 'info' }), + packetBackend: Type.String({ default: 'auto' }), + packetServer: Type.String({ default: '' }) +}); -export class NapCatConfigLoader extends ConfigBase { - constructor(core: NapCatCore, configPath: string) { - super('napcat', core, configPath); +export type NapcatConfig = Static; + +export class NapCatConfigLoader extends ConfigBase { + constructor(core: NapCatCore, configPath: string, schema: AnySchema) { + super('napcat', core, configPath, schema); } } diff --git a/src/core/index.ts b/src/core/index.ts index 5933e2dd..dff28680 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -25,7 +25,7 @@ import fs from 'node:fs'; import { hostname, systemName, systemVersion } from '@/common/system'; import { NTEventWrapper } from '@/common/event'; import { KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types'; -import { NapCatConfigLoader } from '@/core/helper/config'; +import { NapCatConfigLoader, NapcatConfigSchema } from '@/core/helper/config'; import os from 'node:os'; import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners'; import { proxiedListenerOf } from '@/common/proxy-handler'; @@ -99,7 +99,7 @@ export class NapCatCore { this.context = context; this.util = this.context.wrapper.NodeQQNTWrapperUtil; this.eventWrapper = new NTEventWrapper(context.session); - this.configLoader = new NapCatConfigLoader(this, this.context.pathWrapper.configPath); + this.configLoader = new NapCatConfigLoader(this, this.context.pathWrapper.configPath,NapcatConfigSchema); this.apis = { FileApi: new NTQQFileApi(this.context, this), SystemApi: new NTQQSystemApi(this.context, this), diff --git a/src/onebot/config/config.ts b/src/onebot/config/config.ts index 8eccb934..cfa9c4a1 100644 --- a/src/onebot/config/config.ts +++ b/src/onebot/config/config.ts @@ -78,7 +78,7 @@ const NetworkConfigSchema = Type.Object({ plugins: Type.Array(PluginConfigSchema, { default: [] }) }, { default: {} }); -const OneBotConfigSchema = Type.Object({ +export const OneBotConfigSchema = Type.Object({ network: NetworkConfigSchema, musicSignUrl: Type.String({ default: '' }), enableLocalFile2Url: Type.Boolean({ default: false }), diff --git a/src/onebot/config/index.ts b/src/onebot/config/index.ts index 9e80df5a..db81dcdb 100644 --- a/src/onebot/config/index.ts +++ b/src/onebot/config/index.ts @@ -1,9 +1,10 @@ import { ConfigBase } from '@/common/config-base'; import { NapCatCore } from '@/core'; import { OneBotConfig } from './config'; +import { AnySchema } from 'ajv'; export class OB11ConfigLoader extends ConfigBase { - constructor(core: NapCatCore, configPath: string) { - super('onebot11', core, configPath, false); + constructor(core: NapCatCore, configPath: string, schema: AnySchema) { + super('onebot11', core, configPath, schema); } } diff --git a/src/onebot/index.ts b/src/onebot/index.ts index ff8d7260..78b25397 100644 --- a/src/onebot/index.ts +++ b/src/onebot/index.ts @@ -44,8 +44,8 @@ import { LRUCache } from '@/common/lru-cache'; import { BotOfflineEvent } from './event/notice/BotOfflineEvent'; import { NetworkAdapterConfig, - loadConfig, OneBotConfig, + OneBotConfigSchema, } from './config/config'; import { OB11Message } from './types'; import { IOB11NetworkAdapter } from '@/onebot/network/adapter'; @@ -66,9 +66,7 @@ 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.save(this.configLoader.configData); - this.configLoader.save(loadConfig(this.configLoader.configData)); + this.configLoader = new OB11ConfigLoader(core, pathWrapper.configPath, OneBotConfigSchema); this.apis = { GroupApi: new OneBotGroupApi(this, core), UserApi: new OneBotUserApi(this, core), @@ -176,9 +174,6 @@ export class NapCatOneBot11Adapter { WebUiDataRuntime.setQQLoginStatus(true); WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => { const prev = this.configLoader.configData; - // 保证默认配置 - newConfig = loadConfig(newConfig); - this.configLoader.save(newConfig); //this.context.logger.log(`OneBot11 配置更改:${JSON.stringify(prev)} -> ${JSON.stringify(newConfig)}`); await this.reloadNetwork(prev, newConfig);