102 lines
2.8 KiB
TypeScript
102 lines
2.8 KiB
TypeScript
import type { Request, Response, NextFunction } from "express";
|
|
import express from "express";
|
|
import process from "node:process";
|
|
|
|
import adminRouter from "./routes/admin.js";
|
|
import claimsRouter from "./routes/claims.js";
|
|
import open91Router from "./routes/open-91.js";
|
|
import tencentRouter from "./routes/tencent.js";
|
|
import webhooksRouter from "./routes/webhooks.js";
|
|
import { buildSuccessPayload, sendRouteError } from "./utils/http.js";
|
|
import { accessLogMiddleware } from "./middleware/access-log.js";
|
|
import { corsMiddleware } from "./middleware/cors.js";
|
|
import { buildHealthPayload, type StartupState } from "./startup/state.js";
|
|
|
|
type CreateAppOptions = {
|
|
startupState: StartupState;
|
|
isShutdownStarted: () => boolean;
|
|
};
|
|
|
|
export function createApp({
|
|
startupState,
|
|
isShutdownStarted,
|
|
}: CreateAppOptions) {
|
|
const app = express();
|
|
|
|
app.use(accessLogMiddleware);
|
|
app.use(corsMiddleware);
|
|
app.use(express.json({ limit: "2mb" }));
|
|
app.use(express.urlencoded({ extended: true }));
|
|
|
|
app.get("/health", (_req, res) => {
|
|
res.json(
|
|
buildSuccessPayload(
|
|
buildHealthPayload(startupState, isShutdownStarted()),
|
|
startupState.core.ready ? "ready" : "starting"
|
|
)
|
|
);
|
|
});
|
|
|
|
app.get("/health/live", (_req, res) => {
|
|
res.json(
|
|
buildSuccessPayload({
|
|
status: isShutdownStarted() ? "shutting_down" : "alive",
|
|
pid: process.pid,
|
|
})
|
|
);
|
|
});
|
|
|
|
app.get("/health/ready", (_req, res) => {
|
|
if (startupState.core.ready) {
|
|
res.json(
|
|
buildSuccessPayload(
|
|
buildHealthPayload(startupState, isShutdownStarted()),
|
|
"ready"
|
|
)
|
|
);
|
|
return;
|
|
}
|
|
|
|
res.status(503).json({
|
|
code: 1,
|
|
msg: startupState.core.lastError || "服务启动中,请稍后重试",
|
|
errorCode: "service_not_ready",
|
|
time: Math.floor(Date.now() / 1000),
|
|
data: buildHealthPayload(startupState, isShutdownStarted()),
|
|
});
|
|
});
|
|
|
|
app.use((req, res, next) => {
|
|
if (startupState.core.ready) {
|
|
next();
|
|
return;
|
|
}
|
|
|
|
res.status(503).json({
|
|
code: 1,
|
|
msg: startupState.core.lastError || "服务启动中,请稍后重试",
|
|
errorCode: "service_not_ready",
|
|
time: Math.floor(Date.now() / 1000),
|
|
data: {
|
|
startup: {
|
|
phase: startupState.phase,
|
|
attemptCount: startupState.core.attemptCount,
|
|
lastAttemptAt: startupState.core.lastAttemptAt,
|
|
},
|
|
},
|
|
});
|
|
});
|
|
|
|
app.use("/api/v1/tencent", tencentRouter);
|
|
app.use("/api/v1/open/91", open91Router);
|
|
app.use("/api/v1/webhooks", webhooksRouter);
|
|
app.use("/api/v1/claim", claimsRouter);
|
|
app.use("/api/v1/admin", adminRouter);
|
|
|
|
app.use((err: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
|
sendRouteError(res, err, "服务内部错误", "[global]");
|
|
});
|
|
|
|
return app;
|
|
}
|