mirror of
https://github.com/jiangrui1994/CloudSaver.git
synced 2026-01-10 15:18:46 +08:00
Refactor the backend
This commit is contained in:
@@ -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> {
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 || "服务器内部错误",
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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无效");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ export class UserService {
|
||||
globalSetting?.dataValues.CommonUserCode,
|
||||
globalSetting?.dataValues.AdminUserCode,
|
||||
];
|
||||
|
||||
if (!registerCode || !registerCodeList.includes(Number(registerCode))) {
|
||||
throw new Error("注册码错误");
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user