mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-12-05 18:41:56 +00:00
文案模块
This commit is contained in:
parent
6809d07bcf
commit
e775bcdf77
@ -11,6 +11,7 @@ import { WsModule } from './core/ws/ws.module';
|
|||||||
import { SystemWebModule } from './modules/system/systemWeb.module';
|
import { SystemWebModule } from './modules/system/systemWeb.module';
|
||||||
import { BotModule } from './modules/bot/bot.module';
|
import { BotModule } from './modules/bot/bot.module';
|
||||||
import { CdnModule } from './modules/cdn/cdn.module';
|
import { CdnModule } from './modules/cdn/cdn.module';
|
||||||
|
import { WordsModule } from './modules/words/words.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
@ -26,6 +27,7 @@ import { CdnModule } from './modules/cdn/cdn.module';
|
|||||||
SystemWebModule,
|
SystemWebModule,
|
||||||
BotModule,
|
BotModule,
|
||||||
CdnModule,
|
CdnModule,
|
||||||
|
WordsModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class AppModule {}
|
export class AppModule {}
|
||||||
|
|||||||
@ -10,7 +10,14 @@ import { WsAdapter } from '@nestjs/platform-ws';
|
|||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
Logger.log('晶灵核心初始化..');
|
Logger.log('晶灵核心初始化..');
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
app.setGlobalPrefix('api');
|
app.setGlobalPrefix('api', {
|
||||||
|
exclude: [
|
||||||
|
'cdn',
|
||||||
|
{ path: 'cdn/(.*)', method: RequestMethod.ALL },
|
||||||
|
'public',
|
||||||
|
{ path: 'public/(.*)', method: RequestMethod.ALL },
|
||||||
|
],
|
||||||
|
});
|
||||||
app.useGlobalInterceptors(new ResponseInterceptor());
|
app.useGlobalInterceptors(new ResponseInterceptor());
|
||||||
app.useGlobalFilters(new AllExceptionsFilter());
|
app.useGlobalFilters(new AllExceptionsFilter());
|
||||||
const systemService = app.get(SystemService);
|
const systemService = app.get(SystemService);
|
||||||
|
|||||||
@ -55,13 +55,13 @@ export class CdnController {
|
|||||||
description: '由晶灵资源分发服务器(CDN)提供支持',
|
description: '由晶灵资源分发服务器(CDN)提供支持',
|
||||||
})
|
})
|
||||||
async getFile(@Res() res: Response, @Req() req: Request) {
|
async getFile(@Res() res: Response, @Req() req: Request) {
|
||||||
const relativePath = req.url.replace('/api/cdn/', ''); //params.path;
|
const relativePath = req.url.replace('/cdn/', ''); //params.path;
|
||||||
return this.deliverFile(relativePath, res);
|
return this.deliverFile(relativePath, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get('public/files/*')
|
@Get('public/files/*')
|
||||||
async fromPublicFiles(@Res() res: Response, @Req() req: Request) {
|
async fromPublicFiles(@Res() res: Response, @Req() req: Request) {
|
||||||
const relativePath = req.url.replace('/api/public/files/', '');
|
const relativePath = req.url.replace('/public/files/', '');
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`请求 /public/files/${relativePath} → 代理到 /cdn/${relativePath}`,
|
`请求 /public/files/${relativePath} → 代理到 /cdn/${relativePath}`,
|
||||||
);
|
);
|
||||||
@ -70,7 +70,7 @@ export class CdnController {
|
|||||||
|
|
||||||
@Get('public/cdn/*')
|
@Get('public/cdn/*')
|
||||||
async fromPublicCdn(@Req() req: Request, @Res() res: Response) {
|
async fromPublicCdn(@Req() req: Request, @Res() res: Response) {
|
||||||
const relativePath = req.url.replace('/api/public/cdn/', '');
|
const relativePath = req.url.replace('/public/cdn/', '');
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`请求 /public/cdn/${relativePath} → 代理到 /cdn/${relativePath}`,
|
`请求 /public/cdn/${relativePath} → 代理到 /cdn/${relativePath}`,
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,12 +1,4 @@
|
|||||||
import {
|
import { Controller, Post, Inject, UseGuards, Param } from '@nestjs/common';
|
||||||
Controller,
|
|
||||||
Post,
|
|
||||||
Body,
|
|
||||||
UnauthorizedException,
|
|
||||||
Inject,
|
|
||||||
UseGuards,
|
|
||||||
Param,
|
|
||||||
} from '@nestjs/common';
|
|
||||||
import { ApiTags, ApiOperation, ApiBody, ApiProperty } from '@nestjs/swagger';
|
import { ApiTags, ApiOperation, ApiBody, ApiProperty } from '@nestjs/swagger';
|
||||||
import { SystemWebService } from './systemWeb.service';
|
import { SystemWebService } from './systemWeb.service';
|
||||||
import { ToolsService } from '../../core/tools/tools.service';
|
import { ToolsService } from '../../core/tools/tools.service';
|
||||||
|
|||||||
83
src/modules/words/words.controller.ts
Normal file
83
src/modules/words/words.controller.ts
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import {
|
||||||
|
Controller,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
Post,
|
||||||
|
HttpException,
|
||||||
|
HttpStatus,
|
||||||
|
Logger,
|
||||||
|
Inject,
|
||||||
|
UseGuards,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { WordsService } from './words.service';
|
||||||
|
import { TokenAuthGuard } from '../../core/tools/token-auth.guard';
|
||||||
|
import { ApiBody, ApiOperation, ApiProperty } from '@nestjs/swagger';
|
||||||
|
|
||||||
|
class WordsDto {
|
||||||
|
@ApiProperty({
|
||||||
|
description: '文案id',
|
||||||
|
example: 'poke',
|
||||||
|
})
|
||||||
|
id: string;
|
||||||
|
@ApiProperty({
|
||||||
|
description: '密钥',
|
||||||
|
example: '1111',
|
||||||
|
})
|
||||||
|
token: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Controller('words')
|
||||||
|
export class WordsController {
|
||||||
|
private readonly logger = new Logger(WordsController.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@Inject(WordsService) private readonly wordsService: WordsService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取随机文案
|
||||||
|
*/
|
||||||
|
@Get('getText/:id')
|
||||||
|
@ApiOperation({
|
||||||
|
summary: '获取随机文案',
|
||||||
|
})
|
||||||
|
async getText(@Param('id') id: string) {
|
||||||
|
try {
|
||||||
|
const texts = await this.wordsService.loadWordById(id);
|
||||||
|
if (!texts || texts.length === 0) {
|
||||||
|
throw new HttpException(
|
||||||
|
`文案 ${id} 不存在或为空..`,
|
||||||
|
HttpStatus.NOT_FOUND,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const randomIndex = Math.floor(Math.random() * texts.length);
|
||||||
|
return { success: true, data: texts[randomIndex] };
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`getText 失败: ${e?.message}`);
|
||||||
|
throw new HttpException('服务器错误', HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重载文案
|
||||||
|
*/
|
||||||
|
@Post('reloadText/:id')
|
||||||
|
@ApiOperation({
|
||||||
|
summary: '重载某条文案',
|
||||||
|
})
|
||||||
|
@UseGuards(TokenAuthGuard)
|
||||||
|
@ApiBody({ type: WordsDto })
|
||||||
|
async reloadWord(@Param('id') id: string, @Param('token') token: string) {
|
||||||
|
try {
|
||||||
|
const success = await this.wordsService.reloadWord(id);
|
||||||
|
if (success) {
|
||||||
|
return '成功重载..';
|
||||||
|
} else {
|
||||||
|
throw new HttpException('重载失败..', HttpStatus.BAD_REQUEST);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`reloadWord 失败: ${e?.message}`);
|
||||||
|
throw new HttpException('服务器错误', HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
13
src/modules/words/words.module.ts
Normal file
13
src/modules/words/words.module.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { WordsController } from './words.controller';
|
||||||
|
import { WordsService } from './words.service';
|
||||||
|
import { PathModule } from '../../core/path/path.module';
|
||||||
|
import { ToolsModule } from '../../core/tools/tools.module';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
imports: [PathModule, ToolsModule],
|
||||||
|
controllers: [WordsController],
|
||||||
|
providers: [WordsService],
|
||||||
|
exports: [WordsService],
|
||||||
|
})
|
||||||
|
export class WordsModule {}
|
||||||
66
src/modules/words/words.service.ts
Normal file
66
src/modules/words/words.service.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class WordsService {
|
||||||
|
private readonly logger = new Logger(WordsService.name);
|
||||||
|
private wordCache: Record<string, string[]> = {};
|
||||||
|
private readonly clearIntervalMs = 30 * 60 * 1000; // 30min
|
||||||
|
@Inject(PathService)
|
||||||
|
private readonly paths: PathService;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.startAutoClear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private startAutoClear() {
|
||||||
|
setInterval(() => {
|
||||||
|
this.logger.log('清理文案缓存..');
|
||||||
|
this.wordCache = {};
|
||||||
|
}, this.clearIntervalMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从本地加载 json 到内存&返回
|
||||||
|
*/
|
||||||
|
async loadWordById(id: string): Promise<string[] | null> {
|
||||||
|
this.logger.log(`Loading words ${id}..`);
|
||||||
|
if (this.wordCache[id]) return this.wordCache[id];
|
||||||
|
const filePath = path.join(this.paths.get('words'), `${id}.json`);
|
||||||
|
try {
|
||||||
|
const content = await fs.readFile(filePath, 'utf-8');
|
||||||
|
const parsed = JSON.parse(content);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
const texts = parsed.filter((item) => typeof item === 'string');
|
||||||
|
this.wordCache[id] = texts;
|
||||||
|
return texts;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`加载文案失败: ${id}..`, e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 重载 json 到内存
|
||||||
|
*/
|
||||||
|
async reloadWord(id: string): Promise<boolean> {
|
||||||
|
this.logger.log(`重载文案: ${id}..`);
|
||||||
|
const filePath = path.join(this.paths.get('words'), `${id}.json`);
|
||||||
|
try {
|
||||||
|
const content = await fs.readFile(filePath, 'utf-8');
|
||||||
|
const parsed = JSON.parse(content);
|
||||||
|
if (Array.isArray(parsed)) {
|
||||||
|
this.wordCache[id] = parsed.filter((item) => typeof item === 'string');
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.error(`重载文案失败: ${id}`, e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user