refactor: 重构项目目录与代码结构,清理冗余文件
本次提交进行了大规模的项目结构调整: 1. 调整文件目录归属,将模块代码按功能域重新组织 2. 删除多处冗余的DTO、实体类和模块文件 3. 统一了常量、装饰器、工具类的存放位置 4. 修复了`.gitignore`的日志目录匹配规则 5. 新增了健康检查、认证、用户、剧集、订单等核心业务模块
This commit is contained in:
240
src/logs/logs.service.ts
Normal file
240
src/logs/logs.service.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import { Injectable, NotFoundException, Optional } from '@nestjs/common';
|
||||
import { InjectDataSource } from '@nestjs/typeorm';
|
||||
import { DataSource } from 'typeorm';
|
||||
import { PaginatedResponse } from '../../common/dto/paginated-response.dto';
|
||||
import { CreatePlaybackErrorLogDto } from './dto/create-playback-error-log.dto';
|
||||
import { PlaybackErrorLog } from './entities/playback-error-log.entity';
|
||||
import { RequestLog } from './entities/request-log.entity';
|
||||
import {
|
||||
PlaybackErrorLogRecord,
|
||||
RequestLogRecord,
|
||||
} from './interfaces/log-records.interface';
|
||||
|
||||
interface PaginationInput {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class LogsService {
|
||||
private requestLogSequence = 1;
|
||||
private playbackErrorSequence = 1;
|
||||
private readonly requestLogs = new Map<string, RequestLogRecord>();
|
||||
private readonly playbackErrors: PlaybackErrorLogRecord[] = [];
|
||||
|
||||
constructor(
|
||||
@Optional()
|
||||
@InjectDataSource()
|
||||
readonly dataSource?: DataSource,
|
||||
) {}
|
||||
|
||||
async recordRequest(record: Omit<RequestLogRecord, 'id' | 'createdAt'>) {
|
||||
if (!record.requestId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.hasDatabase()) {
|
||||
const repository = this.dataSource.getRepository(RequestLog);
|
||||
const existing = await repository.findOne({
|
||||
where: { requestId: record.requestId },
|
||||
});
|
||||
await repository.save(
|
||||
repository.create({
|
||||
...existing,
|
||||
...record,
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.requestLogs.set(record.requestId, {
|
||||
...record,
|
||||
id: this.requestLogs.get(record.requestId)?.id ?? this.requestLogSequence++,
|
||||
createdAt:
|
||||
this.requestLogs.get(record.requestId)?.createdAt ??
|
||||
new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
async listRequestLogs(
|
||||
pagination: PaginationInput,
|
||||
): Promise<PaginatedResponse<RequestLogRecord>> {
|
||||
if (this.hasDatabase()) {
|
||||
const page = Math.max(pagination.page, 1);
|
||||
const pageSize = Math.min(Math.max(pagination.pageSize, 1), 100);
|
||||
const repository = this.dataSource.getRepository(RequestLog);
|
||||
const [records, total] = await repository.findAndCount({
|
||||
order: { id: 'DESC' },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
});
|
||||
return {
|
||||
list: records.map((record) => this.toRequestLogRecord(record)),
|
||||
pagination: { page, pageSize, total },
|
||||
};
|
||||
}
|
||||
|
||||
const list = Array.from(this.requestLogs.values()).sort(
|
||||
(left, right) => (right.id ?? 0) - (left.id ?? 0),
|
||||
);
|
||||
|
||||
return this.paginate(list, pagination);
|
||||
}
|
||||
|
||||
async getRequestLogOrThrow(requestId: string) {
|
||||
if (this.hasDatabase()) {
|
||||
const log = await this.dataSource
|
||||
.getRepository(RequestLog)
|
||||
.findOne({ where: { requestId } });
|
||||
if (!log) {
|
||||
throw new NotFoundException('Request log not found');
|
||||
}
|
||||
return this.toRequestLogRecord(log);
|
||||
}
|
||||
|
||||
const log = this.requestLogs.get(requestId);
|
||||
if (!log) {
|
||||
throw new NotFoundException('Request log not found');
|
||||
}
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
async createPlaybackError(dto: CreatePlaybackErrorLogDto) {
|
||||
if (this.hasDatabase()) {
|
||||
const repository = this.dataSource.getRepository(PlaybackErrorLog);
|
||||
const log = await repository.save(
|
||||
repository.create({
|
||||
...dto,
|
||||
occurredAt: new Date(dto.occurredAt),
|
||||
}),
|
||||
);
|
||||
return {
|
||||
id: Number(log.id),
|
||||
requestId: log.requestId,
|
||||
};
|
||||
}
|
||||
|
||||
const log: PlaybackErrorLogRecord = {
|
||||
id: this.playbackErrorSequence++,
|
||||
requestId: dto.requestId,
|
||||
dramaId: dto.dramaId,
|
||||
episodeId: dto.episodeId,
|
||||
playUrl: dto.playUrl,
|
||||
playerErrorCode: dto.playerErrorCode,
|
||||
message: dto.message,
|
||||
progressSeconds: dto.progressSeconds,
|
||||
networkType: dto.networkType,
|
||||
device: dto.device,
|
||||
occurredAt: dto.occurredAt,
|
||||
createdAt: new Date().toISOString(),
|
||||
};
|
||||
|
||||
this.playbackErrors.push(log);
|
||||
return {
|
||||
id: log.id,
|
||||
requestId: log.requestId,
|
||||
};
|
||||
}
|
||||
|
||||
async listPlaybackErrors(
|
||||
pagination: PaginationInput,
|
||||
): Promise<PaginatedResponse<PlaybackErrorLogRecord>> {
|
||||
if (this.hasDatabase()) {
|
||||
const page = Math.max(pagination.page, 1);
|
||||
const pageSize = Math.min(Math.max(pagination.pageSize, 1), 100);
|
||||
const repository = this.dataSource.getRepository(PlaybackErrorLog);
|
||||
const [records, total] = await repository.findAndCount({
|
||||
order: { id: 'DESC' },
|
||||
skip: (page - 1) * pageSize,
|
||||
take: pageSize,
|
||||
});
|
||||
return {
|
||||
list: records.map((record) => this.toPlaybackErrorLogRecord(record)),
|
||||
pagination: { page, pageSize, total },
|
||||
};
|
||||
}
|
||||
|
||||
return this.paginate([...this.playbackErrors].reverse(), pagination);
|
||||
}
|
||||
|
||||
async getPlaybackErrorOrThrow(id: number) {
|
||||
if (this.hasDatabase()) {
|
||||
const log = await this.dataSource
|
||||
.getRepository(PlaybackErrorLog)
|
||||
.findOne({ where: { id } });
|
||||
if (!log) {
|
||||
throw new NotFoundException('Playback error log not found');
|
||||
}
|
||||
return this.toPlaybackErrorLogRecord(log);
|
||||
}
|
||||
|
||||
const log = this.playbackErrors.find((item) => item.id === id);
|
||||
if (!log) {
|
||||
throw new NotFoundException('Playback error log not found');
|
||||
}
|
||||
|
||||
return log;
|
||||
}
|
||||
|
||||
private hasDatabase(): this is this & { dataSource: DataSource } {
|
||||
return Boolean(this.dataSource?.isInitialized);
|
||||
}
|
||||
|
||||
private toRequestLogRecord(log: RequestLog): RequestLogRecord {
|
||||
return {
|
||||
id: Number(log.id),
|
||||
requestId: log.requestId,
|
||||
method: log.method,
|
||||
path: log.path,
|
||||
query: log.query,
|
||||
body: log.body,
|
||||
statusCode: log.statusCode,
|
||||
responseCode: log.responseCode,
|
||||
message: log.message,
|
||||
costMs: log.costMs,
|
||||
userId: log.userId ? Number(log.userId) : undefined,
|
||||
adminId: log.adminId ? Number(log.adminId) : undefined,
|
||||
ip: log.ip,
|
||||
userAgent: log.userAgent,
|
||||
errorStack: log.errorStack,
|
||||
createdAt: log.createdAt?.toISOString?.(),
|
||||
};
|
||||
}
|
||||
|
||||
private toPlaybackErrorLogRecord(log: PlaybackErrorLog): PlaybackErrorLogRecord {
|
||||
return {
|
||||
id: Number(log.id),
|
||||
requestId: log.requestId,
|
||||
userId: log.userId ? Number(log.userId) : undefined,
|
||||
dramaId: Number(log.dramaId),
|
||||
episodeId: Number(log.episodeId),
|
||||
playUrl: log.playUrl,
|
||||
playerErrorCode: log.playerErrorCode,
|
||||
message: log.message,
|
||||
progressSeconds: log.progressSeconds,
|
||||
networkType: log.networkType,
|
||||
device: log.device,
|
||||
occurredAt: log.occurredAt.toISOString(),
|
||||
createdAt: log.createdAt?.toISOString?.() ?? new Date().toISOString(),
|
||||
};
|
||||
}
|
||||
|
||||
private paginate<T>(
|
||||
records: T[],
|
||||
input: PaginationInput,
|
||||
): PaginatedResponse<T> {
|
||||
const page = Math.max(input.page, 1);
|
||||
const pageSize = Math.min(Math.max(input.pageSize, 1), 100);
|
||||
const start = (page - 1) * pageSize;
|
||||
|
||||
return {
|
||||
list: records.slice(start, start + pageSize),
|
||||
pagination: {
|
||||
page,
|
||||
pageSize,
|
||||
total: records.length,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user