This commit is contained in:
手瓜一十雪
2025-02-04 18:09:30 +08:00
parent fbde997f7c
commit 11a7f5fade
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 type { NapCatCore } from '@/core';
import json5 from 'json5';
import Ajv, { AnySchema, ValidateFunction } from 'ajv';
export abstract class ConfigBase<T> {
name: string;
core: NapCatCore;
configPath: string;
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.core = core;
this.configPath = configPath;
this.ajv = new Ajv({ useDefaults: true, coerceTypes: true });
this.validate = this.ajv.compile<T>(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);
}
}
}

View File

@@ -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<NapCatConfig> {
constructor(core: NapCatCore, configPath: string) {
super('napcat', core, configPath);
export type NapcatConfig = Static<typeof NapcatConfigSchema>;
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 { 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),

View File

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

View File

@@ -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<OneBotConfig> {
constructor(core: NapCatCore, configPath: string) {
super('onebot11', core, configPath, false);
constructor(core: NapCatCore, configPath: string, schema: AnySchema) {
super('onebot11', core, configPath, schema);
}
}

View File

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