feat:water

This commit is contained in:
Jerry 2025-09-02 13:49:10 +08:00
parent c7108833ed
commit 3200c39a7d
21 changed files with 56 additions and 73 deletions

View File

@ -21,14 +21,14 @@ export class AutoUpdateService {
/**
*
*/
async checkForUpdates(): Promise<boolean> {
public async checkForUpdates(): Promise<boolean> {
return this.checkRepoForUpdates(this.repoPath, 'crystelf-core');
}
/**
*
*/
async checkRepoForUpdates(
public async checkRepoForUpdates(
folderPath: string,
label = '子仓库',
): Promise<boolean> {

View File

@ -16,7 +16,7 @@ export class FilesService {
* @param targetPath
* @param includeFile
*/
async createDir(targetPath = '', includeFile = false): Promise<void> {
public async createDir(targetPath = '', includeFile = false): Promise<void> {
const root = this.paths.get('root');
try {
const dirToCreate = path.isAbsolute(targetPath)

View File

@ -17,7 +17,7 @@ export class PathService {
*
* @param type
*/
get(type?: PathType): string {
public get(type?: PathType): string {
const mappings: Record<PathType, string> = {
root: this.baseDir,
public: path.join(this.baseDir, 'public'),
@ -64,7 +64,7 @@ export class PathService {
* @param targetPath
* @param includeFile
*/
createDir(targetPath: string, includeFile: boolean = false): void {
public createDir(targetPath: string, includeFile: boolean = false): void {
try {
const dirToCreate = includeFile ? path.dirname(targetPath) : targetPath;
fs.mkdirSync(dirToCreate, { recursive: true });
@ -74,30 +74,6 @@ export class PathService {
throw err;
}
}
/**
*
* @param paths
*/
join(...paths: string[]): string {
return path.join(...paths);
}
/**
*
* @param filePath
*/
getExtension(filePath: string): string {
return path.extname(filePath);
}
/**
*
* @param filePath
*/
getBasename(filePath: string): string {
return path.basename(filePath, path.extname(filePath));
}
}
export type PathType =

View File

@ -21,7 +21,7 @@ export class RedisService implements OnModuleInit {
private readonly Persistence: PersistenceService,
) {}
async onModuleInit() {
public async onModuleInit() {
await this.connectWithRetry();
this.setupEventListeners();
}

View File

@ -37,7 +37,7 @@ export class SystemService {
/**
*
*/
checkRestartTime(): number | null {
public checkRestartTime(): number | null {
if (fs.existsSync(this.restartFile)) {
const prev = Number(fs.readFileSync(this.restartFile, 'utf-8'));
const duration = ((Date.now() - prev) / 1000 - 5).toFixed(2);
@ -51,7 +51,7 @@ export class SystemService {
/**
*
*/
async restart(): Promise<void> {
public async restart(): Promise<void> {
this.markRestartTime();
this.logger.warn('服务即将重启..');
await new Promise((resolve) => setTimeout(resolve, 300));
@ -61,7 +61,7 @@ export class SystemService {
/**
*
*/
async checkUpdate(): Promise<void> {
public async checkUpdate(): Promise<void> {
this.logger.debug('检查系统代码更新..');
const updated = await this.autoUpdateService.checkForUpdates();
if (updated) {

View File

@ -19,7 +19,7 @@ export class TokenAuthGuard implements CanActivate {
@Inject(ToolsService) private readonly toolsService: ToolsService,
) {}
canActivate(context: ExecutionContext): boolean {
public canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = request.body?.token || request.headers['x-token']; //两种传入方式

View File

@ -19,7 +19,7 @@ export class ToolsService {
* @param operation
* @param options
*/
async retry<T>(
public async retry<T>(
operation: () => Promise<T>,
options: RetryOptions,
): Promise<T> {
@ -47,14 +47,14 @@ export class ToolsService {
/**
*
*/
getRandomItem<T>(list: T[]): T {
public getRandomItem<T>(list: T[]): T {
return list[Math.floor(Math.random() * list.length)];
}
/**
*
*/
getRandomDelay(min: number, max: number): number {
public getRandomDelay(min: number, max: number): number {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
@ -62,7 +62,7 @@ export class ToolsService {
* token
* @param token token
*/
checkToken(token: string): boolean {
public checkToken(token: string): boolean {
const expected = this.config.get<string>('TOKEN');
if (!expected) {
this.logger.error('环境变量 TOKEN 未配置,无法进行验证!');
@ -75,7 +75,7 @@ export class ToolsService {
* token
* @param token token
*/
tokenCheckFailed(token: string): never {
public tokenCheckFailed(token: string): never {
this.logger.warn(`有个小可爱使用了错误的 token: ${JSON.stringify(token)}`);
throw new UnauthorizedException('token 验证失败..');
}

View File

@ -17,7 +17,7 @@ export class WsClientManager {
* @param id
* @param socket
*/
add(id: ClientID, socket: WebSocket) {
public add(id: ClientID, socket: WebSocket) {
this.clients.set(id, socket);
}
@ -25,7 +25,7 @@ export class WsClientManager {
*
* @param id
*/
remove(id: ClientID) {
public remove(id: ClientID) {
this.clients.delete(id);
}
@ -33,7 +33,7 @@ export class WsClientManager {
*
* @param id
*/
get(id: ClientID): WebSocket | undefined {
public get(id: ClientID): WebSocket | undefined {
return this.clients.get(id);
}
@ -42,7 +42,7 @@ export class WsClientManager {
* @param id
* @param data
*/
async send(id: ClientID, data: any): Promise<boolean> {
public async send(id: ClientID, data: any): Promise<boolean> {
const socket = this.clients.get(id);
if (!socket || socket.readyState !== WebSocket.OPEN) return false;
return this.safeSend(socket, data);
@ -54,7 +54,11 @@ export class WsClientManager {
* @param data
* @param timeout
*/
async sendAndWait(id: ClientID, data: any, timeout = 5000): Promise<any> {
public async sendAndWait(
id: ClientID,
data: any,
timeout = 5000,
): Promise<any> {
const socket = this.clients.get(id);
if (!socket) return;
@ -86,7 +90,7 @@ export class WsClientManager {
* @param requestId id
* @param data
*/
resolvePendingRequest(requestId: string, data: any): boolean {
public resolvePendingRequest(requestId: string, data: any): boolean {
const callback = pendingRequests.get(requestId);
if (callback) {
pendingRequests.delete(requestId);
@ -100,7 +104,7 @@ export class WsClientManager {
* 广
* @param data
*/
async broadcast(data: any): Promise<void> {
public async broadcast(data: any): Promise<void> {
const tasks = Array.from(this.clients.values()).map((socket) => {
if (socket.readyState === WebSocket.OPEN) {
return this.safeSend(socket, data);

View File

@ -17,7 +17,7 @@ export class WsMessageHandler {
this.logger.log(`已注册 ${handlers.length} 个 WS handler`);
}
async handle(socket: AuthenticatedSocket, clientId: string, msg: any) {
public async handle(socket: AuthenticatedSocket, clientId: string, msg: any) {
try {
// 如果是 pendingRequests 的回包
if (

View File

@ -43,7 +43,7 @@ export class WsGateway implements OnGatewayConnection, OnGatewayDisconnect {
* @param client
* @param req
*/
async handleConnection(client: AuthenticatedSocket, req: any) {
public async handleConnection(client: AuthenticatedSocket, req: any) {
const ip = req.socket.remoteAddress || 'unknown';
this.logger.log(`收到来自 ${ip} 的 WebSocket 连接请求..`);
@ -67,7 +67,7 @@ export class WsGateway implements OnGatewayConnection, OnGatewayDisconnect {
*
* @param client
*/
async handleDisconnect(client: AuthenticatedSocket) {
public async handleDisconnect(client: AuthenticatedSocket) {
if (client.heartbeat) clearInterval(client.heartbeat);
if (client.clientId) {
this.wsClientManager.remove(client.clientId);

View File

@ -23,7 +23,7 @@ export class BotController {
@Post('getBotId')
@UseGuards(TokenAuthGuard)
@ApiOperation({ summary: '获取当前连接到核心的全部 botId 数组' })
async postBotsId(@Body() dto: TokenDto) {
public async postBotsId(@Body() dto: TokenDto) {
return this.botService.getBotId();
}
@ -31,14 +31,14 @@ export class BotController {
@UseGuards(TokenAuthGuard)
@ApiOperation({ summary: '获取群聊信息' })
@ApiBody({ type: GroupInfoDto })
async postGroupInfo(@Body() dto: GroupInfoDto) {
public async postGroupInfo(@Body() dto: GroupInfoDto) {
return this.botService.getGroupInfo({ groupId: dto.groupId });
}
@Post('reportBots')
@UseGuards(TokenAuthGuard)
@ApiOperation({ summary: '广播:要求同步群聊信息和 bot 连接情况' })
async reportBots(@Body() dto: TokenDto) {
public async reportBots(@Body() dto: TokenDto) {
const sendMessage = {
type: 'reportBots',
data: {},
@ -51,7 +51,7 @@ export class BotController {
@UseGuards(TokenAuthGuard)
@ApiOperation({ summary: '发送消息到群聊', description: '自动选择bot发送' })
@ApiBody({ type: SendMessageDto })
async sendMessage(@Body() dto: SendMessageDto) {
public async sendMessage(@Body() dto: SendMessageDto) {
const flag = await this.botService.sendMessage(dto.groupId, dto.message);
if (!flag) {
return { message: '消息发送失败' };
@ -63,7 +63,7 @@ export class BotController {
@UseGuards(TokenAuthGuard)
@ApiOperation({ summary: '广播消息到全部群聊', description: '随机延迟' })
@ApiBody({ type: BroadcastDto })
async smartBroadcast(@Body() dto: BroadcastDto) {
public async smartBroadcast(@Body() dto: BroadcastDto) {
await this.botService.broadcastToAllGroups(dto.message);
return { message: '广播任务已开始,正在后台执行..' };
}

View File

@ -24,7 +24,7 @@ export class BotService {
/**
* botId数组
*/
async getBotId(): Promise<{ uin: number; nickName: string }[]> {
public async getBotId(): Promise<{ uin: number; nickName: string }[]> {
this.logger.debug('正在请求获取在线的bot..');
const userPath = this.paths.get('userData');
const botsPath = path.join(userPath, '/crystelfBots');
@ -56,7 +56,7 @@ export class BotService {
*
* @param data
*/
async getGroupInfo(data: {
public async getGroupInfo(data: {
botId?: number;
groupId: number;
clientId?: string;
@ -93,7 +93,7 @@ export class BotService {
* @param groupId
* @param message
*/
async sendMessage(groupId: number, message: string): Promise<boolean> {
public async sendMessage(groupId: number, message: string): Promise<boolean> {
this.logger.log(`发送${message}${groupId}..`);
const sendBot = await this.getGroupBot(groupId);
if (!sendBot) {
@ -117,7 +117,7 @@ export class BotService {
* 广
* @param message 广
*/
async broadcastToAllGroups(message: string): Promise<void> {
public async broadcastToAllGroups(message: string): Promise<void> {
const userPath = this.paths.get('userData');
const botsPath = path.join(userPath, '/crystelfBots');
const dirData = await fs.readdir(botsPath);

View File

@ -54,13 +54,13 @@ export class CdnController {
summary: '获取资源',
description: '由晶灵资源分发服务器(CDN)提供支持',
})
async getFile(@Res() res: Response, @Req() req: Request) {
public async getFile(@Res() res: Response, @Req() req: Request) {
const relativePath = req.url.replace('/cdn/', ''); //params.path;
return this.deliverFile(relativePath, res);
}
@Get('public/files/*')
async fromPublicFiles(@Res() res: Response, @Req() req: Request) {
public async fromPublicFiles(@Res() res: Response, @Req() req: Request) {
const relativePath = req.url.replace('/public/files/', '');
this.logger.debug(
`请求 /public/files/${relativePath} → 代理到 /cdn/${relativePath}`,
@ -69,7 +69,7 @@ export class CdnController {
}
@Get('public/cdn/*')
async fromPublicCdn(@Req() req: Request, @Res() res: Response) {
public async fromPublicCdn(@Req() req: Request, @Res() res: Response) {
const relativePath = req.url.replace('/public/cdn/', '');
this.logger.debug(
`请求 /public/cdn/${relativePath} → 代理到 /cdn/${relativePath}`,

View File

@ -17,7 +17,7 @@ export class CdnService {
*
* @param relativePath
*/
async getFile(relativePath: string): Promise<string | null> {
public async getFile(relativePath: string): Promise<string | null> {
if (!this.filePath) this.filePath = this.paths.get('public');
if (
!this.isValidPath(relativePath) &&

View File

@ -31,7 +31,10 @@ export class MemeController {
@Post('getRandom')
@ApiOperation({ summary: '获取随机表情包' })
@ApiBody({ type: MemeRequestDto })
async getRandomMeme(@Body() dto: MemeRequestDto, @Res() res: Response) {
public async getRandomMeme(
@Body() dto: MemeRequestDto,
@Res() res: Response,
) {
try {
const memePath = await this.memeService.getRandomMemePath(
dto.character,

View File

@ -14,7 +14,7 @@ export class MemeService {
* @param character
* @param status
*/
async getRandomMemePath(
public async getRandomMemePath(
character?: string,
status?: string,
): Promise<string | null> {

View File

@ -32,7 +32,7 @@ export class SystemWebController {
})
@UseGuards(TokenAuthGuard)
@ApiBody({ type: WebServerDto })
async systemRestart(@Param('token') token: string): Promise<string> {
public async systemRestart(@Param('token') token: string): Promise<string> {
this.systemService.systemRestart();
return '核心正在重启..';
}
@ -47,7 +47,7 @@ export class SystemWebController {
})
@UseGuards(TokenAuthGuard)
@ApiBody({ type: WebServerDto })
async getRestartTime(@Param('token') token: string): Promise<string> {
public async getRestartTime(@Param('token') token: string): Promise<string> {
return await this.systemService.getRestartTime();
}
}

View File

@ -15,7 +15,7 @@ export class SystemWebService {
/**
*
*/
async systemRestart(): Promise<void> {
public async systemRestart(): Promise<void> {
this.logger.debug(`有个小可爱正在请求重启核心..`);
await this.system.restart();
}
@ -23,7 +23,7 @@ export class SystemWebService {
/**
*
*/
async getRestartTime(): Promise<string> {
public async getRestartTime(): Promise<string> {
this.logger.debug(`有个小可爱想知道核心重启花了多久..`);
const restartTimePath = path.join(
this.pathService.get('temp'),

View File

@ -46,7 +46,7 @@ export class WordsController {
@Post('getText')
@ApiOperation({ summary: '获取随机文案' })
@ApiBody({ type: WordsDto })
async getText(@Body() dto: WordsDto) {
public async getText(@Body() dto: WordsDto) {
try {
const texts = await this.wordsService.loadWord(dto.type, dto.id);
if (!texts || texts.length === 0) {
@ -76,7 +76,7 @@ export class WordsController {
@ApiOperation({ summary: '重载某条文案' })
@UseGuards(TokenAuthGuard)
@ApiBody({ type: WordsReloadDto })
async reloadWord(@Body() dto: WordsReloadDto) {
public async reloadWord(@Body() dto: WordsReloadDto) {
try {
const success = await this.wordsService.reloadWord(dto.type, dto.id);
if (success) {

View File

@ -47,7 +47,7 @@ export class WordsService {
/**
*
*/
async loadWord(type: string, name: string): Promise<string[] | null> {
public async loadWord(type: string, name: string): Promise<string[] | null> {
const cacheKey = `${type}/${name}`;
this.logger.log(`加载文案 ${cacheKey}..`);
if (this.wordCache[cacheKey]) return this.wordCache[cacheKey];
@ -71,7 +71,7 @@ export class WordsService {
/**
*
*/
async reloadWord(type: string, name: string): Promise<boolean> {
public async reloadWord(type: string, name: string): Promise<boolean> {
const cacheKey = `${type}/${name}`;
this.logger.log(`重载文案: ${cacheKey}..`);
const filePath = path.join(this.paths.get('words'), type, `${name}.json`);

View File

@ -3,7 +3,7 @@ import { Controller, Get } from '@nestjs/common';
@Controller()
export class RootController {
@Get()
getWelcome() {
public getWelcome() {
return {
message: '欢迎使用晶灵核心',
};