Refactor the backend

This commit is contained in:
jiangrui
2025-03-11 00:06:10 +08:00
parent a78ea7e5bd
commit 615149c83f
22 changed files with 338 additions and 84 deletions

View File

@@ -7,7 +7,7 @@ import { DatabaseService } from "./services/DatabaseService";
import { setupMiddlewares } from "./middleware";
import routes from "./routes/api";
import { logger } from "./utils/logger";
import { errorHandler } from "./middleware/errorHandler";
class App {
private app = express();
private databaseService = container.get<DatabaseService>(TYPES.DatabaseService);
@@ -22,6 +22,8 @@ class App {
// 设置路由
this.app.use("/", routes);
// 设置错误处理中间件
this.app.use(errorHandler);
}
public async start(): Promise<void> {

View File

@@ -1,17 +1,22 @@
import { Request, Response } from "express";
import { ApiResponse } from "../core/ApiResponse";
interface ApiResponseData<T> {
data?: T;
message?: string;
}
export abstract class BaseController {
protected async handleRequest<T>(
req: Request,
res: Response,
action: () => Promise<T>
action: () => Promise<ApiResponseData<T>>
): Promise<void> {
try {
const result = await action();
res.json(ApiResponse.success(result));
} catch (error: any) {
res.status(500).json(ApiResponse.error(error?.message || "未知错误"));
res.json(ApiResponse.success(result.data, result.message));
} catch (error: unknown) {
const errorMessage = error instanceof Error ? error.message : "未知错误";
res.status(200).json(ApiResponse.error(errorMessage));
}
}
}

View File

@@ -1,24 +1,9 @@
import { Request, Response } from "express";
import { Cloud115Service } from "../services/Cloud115Service";
import { sendSuccess, sendError } from "../utils/response";
import UserSetting from "../models/UserSetting";
import { BaseController } from "./BaseController";
import { injectable, inject } from "inversify";
import { TYPES } from "../core/types";
const cloud115 = new Cloud115Service();
const setCookie = async (req: Request): Promise<void> => {
const userId = req.user?.userId;
const userSetting = await UserSetting.findOne({
where: { userId },
});
if (userSetting && userSetting.dataValues.cloud115Cookie) {
cloud115.setCookie(userSetting.dataValues.cloud115Cookie);
} else {
throw new Error("请先设置115网盘cookie");
}
};
@injectable()
export class Cloud115Controller extends BaseController {
constructor(@inject(TYPES.Cloud115Service) private cloud115Service: Cloud115Service) {
@@ -34,31 +19,23 @@ export class Cloud115Controller extends BaseController {
}
async getFolderList(req: Request, res: Response): Promise<void> {
try {
await this.handleRequest(req, res, async () => {
const { parentCid } = req.query;
await setCookie(req);
const result = await cloud115.getFolderList(parentCid as string);
sendSuccess(res, result);
} catch (error) {
sendError(res, { message: (error as Error).message || "获取目录列表失败" });
}
await this.cloud115Service.setCookie(req);
return await this.cloud115Service.getFolderList(parentCid as string);
});
}
async saveFile(req: Request, res: Response): Promise<void> {
try {
await this.handleRequest(req, res, async () => {
const { shareCode, receiveCode, fileId, folderId } = req.body;
await setCookie(req);
const result = await cloud115.saveSharedFile({
await this.cloud115Service.setCookie(req);
return await this.cloud115Service.saveSharedFile({
shareCode,
receiveCode,
fileId,
cid: folderId,
});
sendSuccess(res, result);
} catch (error) {
sendError(res, { message: (error as Error).message || "保存文件失败" });
}
});
}
}
export const Cloud115ServiceInstance = cloud115;

View File

@@ -3,7 +3,6 @@ import { injectable, inject } from "inversify";
import { TYPES } from "../core/types";
import { QuarkService } from "../services/QuarkService";
import { BaseController } from "./BaseController";
import { sendSuccess } from "../utils/response";
@injectable()
export class QuarkController extends BaseController {
@@ -15,11 +14,7 @@ export class QuarkController extends BaseController {
await this.handleRequest(req, res, async () => {
const { shareCode, receiveCode } = req.query;
await this.quarkService.setCookie(req);
const result = await this.quarkService.getShareInfo(
shareCode as string,
receiveCode as string
);
sendSuccess(res, result);
return await this.quarkService.getShareInfo(shareCode as string, receiveCode as string);
});
}
@@ -27,16 +22,14 @@ export class QuarkController extends BaseController {
await this.handleRequest(req, res, async () => {
const { parentCid } = req.query;
await this.quarkService.setCookie(req);
const result = await this.quarkService.getFolderList(parentCid as string);
sendSuccess(res, result);
return await this.quarkService.getFolderList(parentCid as string);
});
}
async saveFile(req: Request, res: Response): Promise<void> {
await this.handleRequest(req, res, async () => {
await this.quarkService.setCookie(req);
const result = await this.quarkService.saveSharedFile(req.body);
sendSuccess(res, result);
return await this.quarkService.saveSharedFile(req.body);
});
}
}

View File

@@ -3,7 +3,6 @@ import { injectable, inject } from "inversify";
import { TYPES } from "../core/types";
import { Searcher } from "../services/Searcher";
import { BaseController } from "./BaseController";
import { sendSuccess } from "../utils/response";
@injectable()
export class ResourceController extends BaseController {
@@ -14,12 +13,11 @@ export class ResourceController extends BaseController {
async search(req: Request, res: Response): Promise<void> {
await this.handleRequest(req, res, async () => {
const { keyword, channelId = "", lastMessageId = "" } = req.query;
const result = await this.searcher.searchAll(
return await this.searcher.searchAll(
keyword as string,
channelId as string,
lastMessageId as string
);
sendSuccess(res, result);
});
}
}

View File

@@ -12,7 +12,7 @@ export class SettingController extends BaseController {
async get(req: Request, res: Response): Promise<void> {
await this.handleRequest(req, res, async () => {
const userId = Number(req.user?.userId);
const userId = req.user?.userId;
const role = Number(req.user?.role);
return await this.settingService.getSettings(userId, role);
});
@@ -20,7 +20,7 @@ export class SettingController extends BaseController {
async save(req: Request, res: Response): Promise<void> {
await this.handleRequest(req, res, async () => {
const userId = Number(req.user?.userId);
const userId = req.user?.userId;
const role = Number(req.user?.role);
return await this.settingService.saveSettings(userId, role, req.body);
});

View File

@@ -12,8 +12,8 @@ export class UserController extends BaseController {
async register(req: Request, res: Response): Promise<void> {
await this.handleRequest(req, res, async () => {
const { username, password, code } = req.body;
return await this.userService.register(username, password, code);
const { username, password, registerCode } = req.body;
return await this.userService.register(username, password, registerCode);
});
}

View File

@@ -12,10 +12,10 @@ export class ApiResponse<T> {
}
static success<T>(data?: T, message = "操作成功"): ApiResponse<T> {
return new ApiResponse(true, 200, data, message);
return new ApiResponse(true, 0, data, message);
}
static error(message: string, code = 500): ApiResponse<null> {
static error(message: string, code = 10000): ApiResponse<null> {
return new ApiResponse(false, code, null, message);
}
}

View File

@@ -8,6 +8,8 @@ import { QuarkService } from "./services/QuarkService";
import { Searcher } from "./services/Searcher";
import { DoubanService } from "./services/DoubanService";
import { UserService } from "./services/UserService";
import { ImageService } from "./services/ImageService";
import { SettingService } from "./services/SettingService";
// Controllers
import { Cloud115Controller } from "./controllers/cloud115";
@@ -25,6 +27,8 @@ container.bind<DatabaseService>(TYPES.DatabaseService).to(DatabaseService).inSin
container.bind<Cloud115Service>(TYPES.Cloud115Service).to(Cloud115Service).inSingletonScope();
container.bind<QuarkService>(TYPES.QuarkService).to(QuarkService).inSingletonScope();
container.bind<Searcher>(TYPES.Searcher).to(Searcher).inSingletonScope();
container.bind<ImageService>(TYPES.ImageService).to(ImageService).inSingletonScope();
container.bind<SettingService>(TYPES.SettingService).to(SettingService).inSingletonScope();
container.bind<DoubanService>(TYPES.DoubanService).to(DoubanService).inSingletonScope();
container.bind<UserService>(TYPES.UserService).to(UserService).inSingletonScope();

View File

@@ -16,7 +16,8 @@ export const authMiddleware = async (
res: Response,
next: NextFunction
): Promise<void | Response> => {
if (req.path === "/user/login" || req.path === "/user/register") {
console.log(req.path);
if (req.path === "/user/login" || req.path === "/user/register" || req.path === "/tele-images/") {
return next();
}

View File

@@ -5,7 +5,6 @@ interface CustomError extends Error {
}
export const errorHandler = (err: CustomError, req: Request, res: Response): void => {
console.error(err);
res.status(err.status || 500).json({
success: false,
error: err.message || "服务器内部错误",

View File

@@ -1,14 +1,14 @@
import { Application } from "express";
import { errorHandler } from "./errorHandler";
import express from "express";
import { authMiddleware } from "./auth";
import { requestLogger } from "./requestLogger";
import { rateLimiter } from "./rateLimiter";
import { cors } from "./cors";
export const setupMiddlewares = (app: Application) => {
app.use(express.json());
app.use(cors());
app.use(requestLogger());
app.use(rateLimiter());
app.use(authMiddleware);
app.use(errorHandler);
};

View File

@@ -2,7 +2,7 @@ import { Request, Response, NextFunction } from "express";
const requestCounts = new Map<string, { count: number; timestamp: number }>();
const WINDOW_MS = 60 * 1000; // 1分钟窗口
const MAX_REQUESTS = 60; // 每个IP每分钟最多60个请求
const MAX_REQUESTS = 600; // 每个IP每分钟最多60个请求
export const rateLimiter = () => {
return (req: Request, res: Response, next: NextFunction) => {

View File

@@ -5,7 +5,7 @@ import { injectable } from "inversify";
import { Request } from "express";
import UserSetting from "../models/UserSetting";
import { ICloudService } from "../types/services";
import { logger } from "@/utils/logger";
import { logger } from "../utils/logger";
interface Cloud115ListItem {
cid: string;

View File

@@ -24,7 +24,7 @@ interface sourceItem {
@injectable()
export class Searcher {
private static instance: Searcher;
private api: AxiosInstance;
private api: AxiosInstance | null = null;
constructor() {
this.initAxiosInstance();

View File

@@ -5,7 +5,7 @@ import { Searcher } from "./Searcher";
@injectable()
export class SettingService {
async getSettings(userId: number | undefined, role: number | undefined) {
async getSettings(userId: string | undefined, role: number | undefined) {
if (!userId) {
throw new Error("用户ID无效");
}
@@ -28,7 +28,7 @@ export class SettingService {
};
}
async saveSettings(userId: number | undefined, role: number | undefined, settings: any) {
async saveSettings(userId: string | undefined, role: number | undefined, settings: any) {
if (!userId) {
throw new Error("用户ID无效");
}

View File

@@ -19,7 +19,6 @@ export class UserService {
globalSetting?.dataValues.CommonUserCode,
globalSetting?.dataValues.AdminUserCode,
];
if (!registerCode || !registerCodeList.includes(Number(registerCode))) {
throw new Error("注册码错误");
}

View File

@@ -1,8 +1,8 @@
import winston from "winston";
import { Config } from "../config";
import { config } from "../config";
const logger = winston.createLogger({
level: Config.app.env === "development" ? "debug" : "info",
level: config.app.env === "development" ? "debug" : "info",
format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
transports: [
new winston.transports.File({ filename: "logs/error.log", level: "error" }),
@@ -10,7 +10,7 @@ const logger = winston.createLogger({
],
});
if (Config.app.env !== "production") {
if (config.app.env !== "production") {
logger.add(
new winston.transports.Console({
format: winston.format.simple(),