Merge pull request #760 from NapNeko/config-refactor

refactor
This commit is contained in:
手瓜一十雪
2025-02-04 18:09:57 +08:00
committed by GitHub
6 changed files with 60 additions and 55 deletions

View File

@@ -2,73 +2,72 @@ import path from 'node:path';
import fs from 'node:fs'; import fs from 'node:fs';
import type { NapCatCore } from '@/core'; import type { NapCatCore } from '@/core';
import json5 from 'json5'; import json5 from 'json5';
import Ajv, { AnySchema, ValidateFunction } from 'ajv';
export abstract class ConfigBase<T> { export abstract class ConfigBase<T> {
name: string; name: string;
core: NapCatCore; core: NapCatCore;
configPath: string; configPath: string;
configData: T = {} as T; configData: T = {} as T;
ajv: Ajv;
validate: ValidateFunction<T>;
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.name = name;
this.core = core; this.core = core;
this.configPath = configPath; this.configPath = configPath;
this.ajv = new Ajv({ useDefaults: true, coerceTypes: true });
this.validate = this.ajv.compile<T>(ConfigSchema);
fs.mkdirSync(this.configPath, { recursive: true }); fs.mkdirSync(this.configPath, { recursive: true });
this.read(copy_default); this.read();
} }
protected getKeys(): string[] | null { getConfigPath(pathName?: string): string {
// 决定 key 在json配置文件中的顺序 const filename = pathName ? `${this.name}_${pathName}.json` : `${this.name}.json`;
return null; return path.join(this.configPath, filename);
} }
getConfigPath(pathName: string | undefined): string { read(): T {
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 {
const configPath = this.getConfigPath(this.core.selfInfo.uin); const configPath = this.getConfigPath(this.core.selfInfo.uin);
if (!fs.existsSync(configPath) && copy_default) { const defaultConfigPath = this.getConfigPath();
try { if (!fs.existsSync(configPath)) {
fs.writeFileSync(configPath, fs.readFileSync(this.getConfigPath(undefined), 'utf-8')); if (fs.existsSync(defaultConfigPath)) {
this.core.context.logger.log('[Core] [Config] 配置文件创建成功!\n'); this.configData = this.loadConfig(defaultConfigPath);
} catch (e: unknown) {
this.core.context.logger.logError('[Core] [Config] 创建配置文件时发生错误:', (e as Error).message);
} }
} else if (!fs.existsSync(configPath) && !copy_default) { this.validate(this.configData);
fs.writeFileSync(configPath, '{}'); this.save();
return this.configData;
} }
return this.loadConfig(configPath);
}
private loadConfig(configPath: string): T {
try { try {
this.configData = json5.parse(fs.readFileSync(configPath, 'utf-8')); this.configData = json5.parse(fs.readFileSync(configPath, 'utf-8'));
this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData); this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
return this.configData; return this.configData;
} catch (e: unknown) { } catch (e: unknown) {
if (e instanceof SyntaxError) { this.handleError(e, '读取配置文件时发生错误');
this.core.context.logger.logError('[Core] [Config] 配置文件格式错误,请检查配置文件:', e.message);
} else {
this.core.context.logger.logError('[Core] [Config] 读取配置文件时发生错误:', (e as Error).message);
}
return {} as T; return {} as T;
} }
} }
save(newConfigData: T = this.configData): void {
save(newConfigData: T = this.configData) { const configPath = this.getConfigPath(this.core.selfInfo.uin);
const selfInfo = this.core.selfInfo; this.validate(newConfigData);
this.configData = newConfigData; this.configData = newConfigData;
const configPath = this.getConfigPath(selfInfo.uin);
try { try {
fs.writeFileSync(configPath, JSON.stringify(newConfigData, this.getKeys(), 2)); fs.writeFileSync(configPath, JSON.stringify(this.configData, null, 2));
} catch (e: unknown) { } 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);
}
}
}

View File

@@ -1,11 +1,21 @@
import { ConfigBase } from '@/common/config-base'; import { ConfigBase } from '@/common/config-base';
import napCatDefaultConfig from '@/core/external/napcat.json';
import { NapCatCore } from '@/core'; 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<NapCatConfig> { export type NapcatConfig = Static<typeof NapcatConfigSchema>;
constructor(core: NapCatCore, configPath: string) {
super('napcat', core, configPath); export class NapCatConfigLoader extends ConfigBase<NapcatConfig> {
constructor(core: NapCatCore, configPath: string, schema: AnySchema) {
super('napcat', core, configPath, schema);
} }
} }

View File

@@ -25,7 +25,7 @@ import fs from 'node:fs';
import { hostname, systemName, systemVersion } from '@/common/system'; import { hostname, systemName, systemVersion } from '@/common/system';
import { NTEventWrapper } from '@/common/event'; import { NTEventWrapper } from '@/common/event';
import { KickedOffLineInfo, SelfInfo, SelfStatusInfo } from '@/core/types'; 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 os from 'node:os';
import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners'; import { NodeIKernelMsgListener, NodeIKernelProfileListener } from '@/core/listeners';
import { proxiedListenerOf } from '@/common/proxy-handler'; import { proxiedListenerOf } from '@/common/proxy-handler';
@@ -99,7 +99,7 @@ export class NapCatCore {
this.context = context; this.context = context;
this.util = this.context.wrapper.NodeQQNTWrapperUtil; this.util = this.context.wrapper.NodeQQNTWrapperUtil;
this.eventWrapper = new NTEventWrapper(context.session); 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 = { this.apis = {
FileApi: new NTQQFileApi(this.context, this), FileApi: new NTQQFileApi(this.context, this),
SystemApi: new NTQQSystemApi(this.context, this), SystemApi: new NTQQSystemApi(this.context, this),

View File

@@ -78,7 +78,7 @@ const NetworkConfigSchema = Type.Object({
plugins: Type.Array(PluginConfigSchema, { default: [] }) plugins: Type.Array(PluginConfigSchema, { default: [] })
}, { default: {} }); }, { default: {} });
const OneBotConfigSchema = Type.Object({ export const OneBotConfigSchema = Type.Object({
network: NetworkConfigSchema, network: NetworkConfigSchema,
musicSignUrl: Type.String({ default: '' }), musicSignUrl: Type.String({ default: '' }),
enableLocalFile2Url: Type.Boolean({ default: false }), enableLocalFile2Url: Type.Boolean({ default: false }),

View File

@@ -1,9 +1,10 @@
import { ConfigBase } from '@/common/config-base'; import { ConfigBase } from '@/common/config-base';
import { NapCatCore } from '@/core'; import { NapCatCore } from '@/core';
import { OneBotConfig } from './config'; import { OneBotConfig } from './config';
import { AnySchema } from 'ajv';
export class OB11ConfigLoader extends ConfigBase<OneBotConfig> { export class OB11ConfigLoader extends ConfigBase<OneBotConfig> {
constructor(core: NapCatCore, configPath: string) { constructor(core: NapCatCore, configPath: string, schema: AnySchema) {
super('onebot11', core, configPath, false); super('onebot11', core, configPath, schema);
} }
} }

View File

@@ -44,8 +44,8 @@ import { LRUCache } from '@/common/lru-cache';
import { BotOfflineEvent } from './event/notice/BotOfflineEvent'; import { BotOfflineEvent } from './event/notice/BotOfflineEvent';
import { import {
NetworkAdapterConfig, NetworkAdapterConfig,
loadConfig,
OneBotConfig, OneBotConfig,
OneBotConfigSchema,
} from './config/config'; } from './config/config';
import { OB11Message } from './types'; import { OB11Message } from './types';
import { IOB11NetworkAdapter } from '@/onebot/network/adapter'; import { IOB11NetworkAdapter } from '@/onebot/network/adapter';
@@ -66,9 +66,7 @@ export class NapCatOneBot11Adapter {
constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) { constructor(core: NapCatCore, context: InstanceContext, pathWrapper: NapCatPathWrapper) {
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, OneBotConfigSchema);
this.configLoader.save(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),
@@ -176,9 +174,6 @@ export class NapCatOneBot11Adapter {
WebUiDataRuntime.setQQLoginStatus(true); WebUiDataRuntime.setQQLoginStatus(true);
WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => { WebUiDataRuntime.setOnOB11ConfigChanged(async (newConfig) => {
const prev = this.configLoader.configData; const prev = this.configLoader.configData;
// 保证默认配置
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)}`);
await this.reloadNetwork(prev, newConfig); await this.reloadNetwork(prev, newConfig);