From de264b1244e14ad479f133fbfc7a8de86f3ed0fa Mon Sep 17 00:00:00 2001 From: Jerryplusy Date: Mon, 25 Aug 2025 22:59:44 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=87=E6=A1=88=E6=A8=A1=E5=9D=97=E4=BC=98?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/auto-update/auto-update.service.ts | 84 +++++++++++++-------- src/core/path/path.service.ts | 2 +- src/modules/words/words.controller.ts | 2 +- src/modules/words/words.service.ts | 33 +++++++- 4 files changed, 84 insertions(+), 37 deletions(-) diff --git a/src/core/auto-update/auto-update.service.ts b/src/core/auto-update/auto-update.service.ts index fda190f..4ec7063 100644 --- a/src/core/auto-update/auto-update.service.ts +++ b/src/core/auto-update/auto-update.service.ts @@ -13,57 +13,65 @@ export class AutoUpdateService { private readonly git: SimpleGit; private readonly repoPath: string; - constructor( - @Inject(PathService) - private readonly pathService: PathService, - ) { + constructor(@Inject(PathService) private readonly pathService: PathService) { this.git = simpleGit(); this.repoPath = this.pathService.get('root'); } /** - * 检查远程更新 + * 检查主仓库远程更新 */ async checkForUpdates(): Promise { - try { - this.logger.log('检查仓库更新中...'); + return this.checkRepoForUpdates(this.repoPath, 'crystelf-core'); + } + + /** + * 检查指定文件夹的更新 + */ + async checkRepoForUpdates( + folderPath: string, + label = '子仓库', + ): Promise { + try { + this.logger.log(`[${label}] 检查仓库更新中...`); + + const repoGit = simpleGit(folderPath); + const status = await repoGit.status(); - const status = await this.git.status(); if (status.ahead > 0) { - this.logger.warn('检测到本地仓库有未提交的更改,跳过更新'); + this.logger.warn(`[${label}] 检测到本地仓库有未提交的更改,跳过更新`); return false; } - this.logger.log('正在获取远程仓库信息...'); - await this.git.fetch(); + this.logger.log(`[${label}] 正在获取远程仓库信息...`); + await repoGit.fetch(); const localBranch = status.current; - const diffSummary = await this.git.diffSummary([ + const diffSummary = await repoGit.diffSummary([ `${localBranch}..origin/${localBranch}`, ]); if (diffSummary.files.length > 0) { - this.logger.log('检测到远程仓库有更新!'); - + this.logger.log(`[${label}] 检测到远程仓库有更新!`); if (localBranch) { - this.logger.log('正在拉取远程代码...'); - await this.git.pull('origin', localBranch); + this.logger.log(`[${label}] 正在拉取远程代码...`); + await repoGit.pull('origin', localBranch); } else { - this.logger.error('当前分支名称未知,无法执行拉取操作。'); + this.logger.error(`[${label}] 当前分支名称未知,无法执行拉取操作。`); return false; } - this.logger.log('代码更新成功,开始更新依赖...'); - await this.updateDependencies(); + this.logger.log(`[${label}] 代码更新成功,开始更新依赖...`); + await this.updateDependencies(folderPath, label); - this.logger.log('自动更新流程完成'); + this.logger.log(`[${label}] 自动更新流程完成`); return true; } else { - this.logger.log('远程仓库没有新变化'); + this.logger.log(`[${label}] 远程仓库没有新变化`); return false; } } catch (error) { - this.logger.error('检查仓库更新失败:', error); + this.logger.error(`[${label}] 检查仓库更新失败:`, error); return false; } } @@ -71,24 +79,34 @@ export class AutoUpdateService { /** * 自动安装依赖和构建 */ - private async updateDependencies(): Promise { + private async updateDependencies( + folderPath: string, + label = '仓库', + ): Promise { try { - this.logger.log('执行 pnpm install...'); - await execAsync('pnpm install', { cwd: this.repoPath }); - this.logger.log('依赖安装完成'); + this.logger.log(`[${label}] 执行 pnpm install...`); + await execAsync('pnpm install', { cwd: folderPath }); + this.logger.log(`[${label}] 依赖安装完成`); - const pkgPath = this.pathService.get('package'); - const pkgJson = JSON.parse(readFileSync(pkgPath, 'utf-8')); + const pkgPath = `${folderPath}/package.json`; + let pkgJson: any; + + try { + pkgJson = JSON.parse(readFileSync(pkgPath, 'utf-8')); + } catch { + this.logger.warn(`[${label}] 未找到 package.json,跳过依赖构建`); + return; + } if (pkgJson.scripts?.build) { - this.logger.log('检测到 build 脚本,执行 pnpm build...'); - await execAsync('pnpm build', { cwd: this.repoPath }); - this.logger.log('构建完成'); + this.logger.log(`[${label}] 检测到 build 脚本,执行 pnpm build...`); + await execAsync('pnpm build', { cwd: folderPath }); + this.logger.log(`[${label}] 构建完成`); } else { - this.logger.log('未检测到 build 脚本,跳过构建'); + this.logger.log(`[${label}] 未检测到 build 脚本,跳过构建`); } } catch (error) { - this.logger.error('更新依赖或构建失败:', error); + this.logger.error(`[${label}] 更新依赖或构建失败:`, error); } } } diff --git a/src/core/path/path.service.ts b/src/core/path/path.service.ts index d478692..353632b 100644 --- a/src/core/path/path.service.ts +++ b/src/core/path/path.service.ts @@ -27,7 +27,7 @@ export class PathService { userData: path.join(this.baseDir, 'private/data'), package: path.join(this.baseDir, 'package.json'), modules: path.join(this.baseDir, 'src/modules'), - words: path.join(this.baseDir, 'private/data/word'), + words: path.join(this.baseDir, 'private/word'), }; return type ? mappings[type] : this.baseDir; diff --git a/src/modules/words/words.controller.ts b/src/modules/words/words.controller.ts index e389eb9..d528171 100644 --- a/src/modules/words/words.controller.ts +++ b/src/modules/words/words.controller.ts @@ -51,7 +51,7 @@ export class WordsController { ); } const randomIndex = Math.floor(Math.random() * texts.length); - return { success: true, data: texts[randomIndex] }; + return texts[randomIndex]; } catch (e) { this.logger.error(`getText 失败: ${e?.message}`); throw new HttpException('服务器错误', HttpStatus.INTERNAL_SERVER_ERROR); diff --git a/src/modules/words/words.service.ts b/src/modules/words/words.service.ts index a85f137..4ca9522 100644 --- a/src/modules/words/words.service.ts +++ b/src/modules/words/words.service.ts @@ -2,19 +2,28 @@ import { Inject, Injectable, Logger } from '@nestjs/common'; import * as path from 'path'; import * as fs from 'fs/promises'; import { PathService } from '../../core/path/path.service'; +import { AutoUpdateService } from '../../core/auto-update/auto-update.service'; @Injectable() export class WordsService { private readonly logger = new Logger(WordsService.name); private wordCache: Record = {}; private readonly clearIntervalMs = 30 * 60 * 1000; // 30min + @Inject(PathService) private readonly paths: PathService; + @Inject(AutoUpdateService) + private readonly autoUpdateService: AutoUpdateService; + constructor() { this.startAutoClear(); + this.startAutoUpdate(); } + /** + * 启动定时清理缓存 + */ private startAutoClear() { setInterval(() => { this.logger.log('清理文案缓存..'); @@ -23,10 +32,30 @@ export class WordsService { } /** - * 从本地加载 json 到内存&返回 + * 启动定时检查 words 仓库更新 + */ + private startAutoUpdate() { + const wordsPath = this.paths.get('words'); + + setInterval(async () => { + this.logger.log('定时检查文案仓库更新..'); + const updated = await this.autoUpdateService.checkRepoForUpdates( + wordsPath, + 'words 仓库', + ); + + if (updated) { + this.logger.log('文案仓库已更新,清理缓存..'); + this.wordCache = {}; + } + }, this.clearIntervalMs); + } + + /** + * 从本地加载文案到内存 */ async loadWordById(id: string): Promise { - this.logger.log(`Loading words ${id}..`); + this.logger.log(`加载文案 ${id}..`); if (this.wordCache[id]) return this.wordCache[id]; const filePath = path.join(this.paths.get('words'), `${id}.json`); try {