迁移类型校验到zod

This commit is contained in:
手瓜一十雪
2025-04-13 20:05:11 +08:00
parent 4084e431ec
commit 8a116d2d7b
101 changed files with 951 additions and 945 deletions

View File

@@ -2,22 +2,20 @@ 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';
import { z } from 'zod';
export abstract class ConfigBase<T> {
name: string;
core: NapCatCore;
configPath: string;
configData: T = {} as T;
ajv: Ajv;
validate: ValidateFunction<T>;
schema: z.ZodType<T>;
protected constructor(name: string, core: NapCatCore, configPath: string, ConfigSchema: AnySchema) {
protected constructor(name: string, core: NapCatCore, configPath: string, schema: z.ZodType<T>) {
this.name = name;
this.core = core;
this.configPath = configPath;
this.ajv = new Ajv({ useDefaults: true, coerceTypes: true });
this.validate = this.ajv.compile<T>(ConfigSchema);
this.schema = schema;
fs.mkdirSync(this.configPath, { recursive: true });
this.read();
}
@@ -42,11 +40,16 @@ export abstract class ConfigBase<T> {
private loadConfig(configPath: string): T {
try {
let newConfigData = json5.parse(fs.readFileSync(configPath, 'utf-8'));
this.validate(newConfigData);
this.configData = newConfigData;
this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
return this.configData;
let configData = json5.parse(fs.readFileSync(configPath, 'utf-8'));
const result = this.schema.safeParse(configData);
if (result.success) {
this.configData = result.data;
this.core.context.logger.logDebug(`[Core] [Config] 配置文件${configPath}加载`, this.configData);
return this.configData;
} else {
throw new Error(`配置文件验证失败: ${result.error.message}`);
}
} catch (e: unknown) {
this.handleError(e, '读取配置文件时发生错误');
return {} as T;
@@ -55,10 +58,14 @@ export abstract class ConfigBase<T> {
save(newConfigData: T = this.configData): void {
const configPath = this.getConfigPath(this.core.selfInfo.uin);
this.validate(newConfigData);
this.configData = newConfigData;
try {
fs.writeFileSync(configPath, JSON.stringify(this.configData, null, 2));
const result = this.schema.safeParse(newConfigData);
if (result.success) {
this.configData = result.data;
fs.writeFileSync(configPath, JSON.stringify(this.configData, null, 2));
} else {
throw new Error(`配置文件验证失败: ${result.error.message}`);
}
} catch (e: unknown) {
this.handleError(e, `保存配置文件 ${configPath} 时发生错误:`);
}
@@ -67,6 +74,8 @@ export abstract class ConfigBase<T> {
private handleError(e: unknown, message: string): void {
if (e instanceof SyntaxError) {
this.core.context.logger.logError('[Core] [Config] 操作配置文件格式错误,请检查配置文件:', e.message);
} else if (e instanceof z.ZodError) {
this.core.context.logger.logError('[Core] [Config] 配置文件验证错误:', e.message);
} else {
this.core.context.logger.logError(`[Core] [Config] ${message}:`, (e as Error).message);
}

View File

@@ -128,7 +128,7 @@ class FFmpegService {
const [fileInfo, durationInfo] = await Promise.all([
// 任务1: 获取文件信息和提取缩略图
(async () => {
sendLog(`开始任务1: 获取文件信息和提取缩略图`);
sendLog('开始任务1: 获取文件信息和提取缩略图');
// 获取文件信息 (并行)
const fileInfoStartTime = Date.now();
@@ -147,7 +147,7 @@ class FFmpegService {
// 直接实现缩略图提取 (不调用extractThumbnail方法)
const thumbStartTime = Date.now();
sendLog(`开始提取缩略图`);
sendLog('开始提取缩略图');
const ffmpegInstance = await withTimeout(
FFmpeg.create({ core: '@ffmpeg.wasm/core-mt' }),
@@ -215,7 +215,7 @@ class FFmpegService {
// 任务2: 获取视频时长
(async () => {
const task2StartTime = Date.now();
sendLog(`开始任务2: 获取视频时长`);
sendLog('开始任务2: 获取视频时长');
// 创建FFmpeg实例
const ffmpegCreateStartTime = Date.now();
@@ -291,16 +291,16 @@ interface FFmpegTask {
}
export default async function handleFFmpegTask({ method, args }: FFmpegTask): Promise<any> {
switch (method) {
case 'extractThumbnail':
return await FFmpegService.extractThumbnail(...args as [string, string]);
case 'convertFile':
return await FFmpegService.convertFile(...args as [string, string, string]);
case 'convert':
return await FFmpegService.convert(...args as [string, string]);
case 'getVideoInfo':
return await FFmpegService.getVideoInfo(...args as [string, string]);
default:
throw new Error(`Unknown method: ${method}`);
case 'extractThumbnail':
return await FFmpegService.extractThumbnail(...args as [string, string]);
case 'convertFile':
return await FFmpegService.convertFile(...args as [string, string, string]);
case 'convert':
return await FFmpegService.convert(...args as [string, string]);
case 'getVideoInfo':
return await FFmpegService.getVideoInfo(...args as [string, string]);
default:
throw new Error(`Unknown method: ${method}`);
}
}
recvTask<FFmpegTask>(async ({ method, args }: FFmpegTask) => {

View File

@@ -182,28 +182,28 @@ export async function uriToLocalFile(dir: string, uri: string, filename: string
const filePath = path.join(dir, filename);
switch (UriType) {
case FileUriType.Local: {
const fileExt = path.extname(HandledUri);
const localFileName = path.basename(HandledUri, fileExt) + fileExt;
const tempFilePath = path.join(dir, filename + fileExt);
fs.copyFileSync(HandledUri, tempFilePath);
return { success: true, errMsg: '', fileName: localFileName, path: tempFilePath };
}
case FileUriType.Local: {
const fileExt = path.extname(HandledUri);
const localFileName = path.basename(HandledUri, fileExt) + fileExt;
const tempFilePath = path.join(dir, filename + fileExt);
fs.copyFileSync(HandledUri, tempFilePath);
return { success: true, errMsg: '', fileName: localFileName, path: tempFilePath };
}
case FileUriType.Remote: {
const buffer = await httpDownload({ url: HandledUri, headers: headers ?? {} });
fs.writeFileSync(filePath, buffer);
return { success: true, errMsg: '', fileName: filename, path: filePath };
}
case FileUriType.Remote: {
const buffer = await httpDownload({ url: HandledUri, headers: headers ?? {} });
fs.writeFileSync(filePath, buffer);
return { success: true, errMsg: '', fileName: filename, path: filePath };
}
case FileUriType.Base64: {
const base64 = HandledUri.replace(/^base64:\/\//, '');
const base64Buffer = Buffer.from(base64, 'base64');
fs.writeFileSync(filePath, base64Buffer);
return { success: true, errMsg: '', fileName: filename, path: filePath };
}
case FileUriType.Base64: {
const base64 = HandledUri.replace(/^base64:\/\//, '');
const base64Buffer = Buffer.from(base64, 'base64');
fs.writeFileSync(filePath, base64Buffer);
return { success: true, errMsg: '', fileName: filename, path: filePath };
}
default:
return { success: false, errMsg: `识别URL失败, uri= ${uri}`, fileName: '', path: '' };
default:
return { success: false, errMsg: `识别URL失败, uri= ${uri}`, fileName: '', path: '' };
}
}

View File

@@ -9,7 +9,7 @@ export async function runTask<T, R>(workerScript: string, taskData: T): Promise<
console.error('Worker Log--->:', (result as { log: string }).log);
}
if ((result as any)?.error) {
reject(new Error("Worker error: " + (result as { error: string }).error));
reject(new Error('Worker error: ' + (result as { error: string }).error));
}
resolve(result);
});