mirror of
https://github.com/crystelf/crystelf-core.git
synced 2025-12-05 10:31:56 +00:00
feat:water
This commit is contained in:
parent
c7108833ed
commit
3200c39a7d
@ -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> {
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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 =
|
||||
|
||||
@ -21,7 +21,7 @@ export class RedisService implements OnModuleInit {
|
||||
private readonly Persistence: PersistenceService,
|
||||
) {}
|
||||
|
||||
async onModuleInit() {
|
||||
public async onModuleInit() {
|
||||
await this.connectWithRetry();
|
||||
this.setupEventListeners();
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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']; //两种传入方式
|
||||
|
||||
|
||||
@ -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 验证失败..');
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 (
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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: '广播任务已开始,正在后台执行..' };
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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}`,
|
||||
|
||||
@ -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) &&
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -14,7 +14,7 @@ export class MemeService {
|
||||
* @param character 角色
|
||||
* @param status 状态
|
||||
*/
|
||||
async getRandomMemePath(
|
||||
public async getRandomMemePath(
|
||||
character?: string,
|
||||
status?: string,
|
||||
): Promise<string | null> {
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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'),
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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`);
|
||||
|
||||
@ -3,7 +3,7 @@ import { Controller, Get } from '@nestjs/common';
|
||||
@Controller()
|
||||
export class RootController {
|
||||
@Get()
|
||||
getWelcome() {
|
||||
public getWelcome() {
|
||||
return {
|
||||
message: '欢迎使用晶灵核心',
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user