feat:优化

This commit is contained in:
Jerry 2025-10-12 14:28:37 +08:00
parent baf92f470a
commit 426fb886ae

View File

@ -4,10 +4,15 @@ import * as fs from 'fs/promises';
import { PathService } from '../../core/path/path.service';
import { AutoUpdateService } from '../../core/auto-update/auto-update.service';
interface WordCacheEntry {
data: string[];
timer: NodeJS.Timeout;
}
@Injectable()
export class WordsService {
private readonly logger = new Logger(WordsService.name);
private wordCache: Record<string, string[]> = {};
private wordCache: Map<string, WordCacheEntry> = new Map();
private readonly clearIntervalMs = 240 * 60 * 1000; // 240min
private readonly updateMs = 15 * 60 * 1000; // 15min
@ -18,21 +23,12 @@ export class WordsService {
private readonly autoUpdateService: AutoUpdateService;
constructor() {
this.startAutoClear();
this.startAutoUpdate();
}
private startAutoClear() {
setInterval(() => {
this.logger.log('清理文案缓存..');
this.wordCache = {};
}, this.clearIntervalMs);
}
private startAutoUpdate() {
setInterval(async () => {
const wordsPath = path.join(this.paths.get('words'), '..');
//const wordsPath = this.paths.get('words');
this.logger.log('定时检查文案仓库更新..');
const updated = await this.autoUpdateService.checkRepoForUpdates(
wordsPath,
@ -40,26 +36,51 @@ export class WordsService {
);
if (updated) {
this.logger.log('文案仓库已更新,清理缓存..');
this.wordCache = {};
this.clearAllCache();
}
}, this.updateMs);
}
private clearAllCache() {
for (const [key, entry] of this.wordCache.entries()) {
clearTimeout(entry.timer);
this.wordCache.delete(key);
}
}
private scheduleCacheClear(key: string) {
const existing = this.wordCache.get(key);
if (existing) clearTimeout(existing.timer);
return setTimeout(() => {
this.logger.log(`清理单项文案缓存: ${key}`);
this.wordCache.delete(key);
}, this.clearIntervalMs);
}
/**
*
*/
public async loadWord(type: string, name: string): Promise<string[] | null> {
const cacheKey = `${type}/${name}`;
const safeType = this.safePathSegment(type);
const safeName = this.safePathSegment(name);
const cacheKey = `${safeType}/${safeName}`;
this.logger.log(`加载文案 ${cacheKey}..`);
if (this.wordCache[cacheKey]) return this.wordCache[cacheKey];
const cache = this.wordCache.get(cacheKey);
if (cache) return cache.data;
const filePath = path.join(this.paths.get('words'), type, `${name}.json`);
const filePath = path.join(
this.paths.get('words'),
safeType,
`${safeName}.json`,
);
try {
const content = await fs.readFile(filePath, 'utf-8');
const content = await fs.readFile(filePath, { encoding: 'utf-8' });
const parsed = JSON.parse(content);
if (Array.isArray(parsed)) {
const texts = parsed.filter((item) => typeof item === 'string');
this.wordCache[cacheKey] = texts;
const timer = this.scheduleCacheClear(cacheKey);
this.wordCache.set(cacheKey, { data: texts, timer });
return texts;
}
return null;
@ -73,16 +94,22 @@ export class WordsService {
*
*/
public async reloadWord(type: string, name: string): Promise<boolean> {
const cacheKey = `${type}/${name}`;
const safeType = this.safePathSegment(type);
const safeName = this.safePathSegment(name);
const cacheKey = `${safeType}/${safeName}`;
this.logger.log(`重载文案: ${cacheKey}..`);
const filePath = path.join(this.paths.get('words'), type, `${name}.json`);
const filePath = path.join(
this.paths.get('words'),
safeType,
`${safeName}.json`,
);
try {
const content = await fs.readFile(filePath, 'utf-8');
const content = await fs.readFile(filePath, { encoding: 'utf-8' });
const parsed = JSON.parse(content);
if (Array.isArray(parsed)) {
this.wordCache[cacheKey] = parsed.filter(
(item) => typeof item === 'string',
);
const texts = parsed.filter((item) => typeof item === 'string');
const timer = this.scheduleCacheClear(cacheKey);
this.wordCache.set(cacheKey, { data: texts, timer });
return true;
}
return false;
@ -91,4 +118,9 @@ export class WordsService {
return false;
}
}
private safePathSegment(segment: string): string {
// 将不安全字符转义为安全文件名形式
return segment.replace(/[\\\/:*?"<>|]/g, '_');
}
}