- POST /api/v1/open/affiliate-dash:验签 → 查任务(404 重试) → webhook_events 幂等闸门 → 状态同步 - migration 013:webhook_events(provider+event_id 唯一) - task-repo findAffiliateDashTaskByOrder(仿 feifei 同构 SQL) - notify-service:去重闸门在找到任务之后,任务未匹配不被 eventId 永久拦截 - typecheck + 212 测试通过;前置错误分支脚本验证通过
114 lines
3.5 KiB
TypeScript
114 lines
3.5 KiB
TypeScript
import type { NextFunction, Request, Response } from 'express'
|
|
import express from 'express'
|
|
import process from 'node:process'
|
|
|
|
import adminRouter from './routes/admin.js'
|
|
import affiliateDashRouter from './routes/affiliate-dash.js'
|
|
import collectRouter from './routes/collect.js'
|
|
import filesRouter from './routes/files.js'
|
|
import claimsRouter from './routes/claims.js'
|
|
import kuaishouFeifeiRouter from './routes/kuaishou-feifei.js'
|
|
import kuaishouIndustryRouter from './routes/kuaishou-industry.js'
|
|
import open91Router from './routes/open-91.js'
|
|
import shortLinksRouter from './routes/short-links.js'
|
|
import workerRouter from './routes/worker.js'
|
|
import { accessLogMiddleware } from './middleware/access-log.js'
|
|
import { createCorsMiddleware } from './middleware/cors.js'
|
|
import { buildHealthPayload, type StartupState } from './startup/state.js'
|
|
import type { RuntimeConfig } from './types/runtime-config.js'
|
|
import { buildSuccessPayload, sendRouteError } from './utils/http.js'
|
|
|
|
type CreateAppOptions = {
|
|
startupState: StartupState
|
|
isShutdownStarted: () => boolean
|
|
config: RuntimeConfig
|
|
}
|
|
|
|
export function createApp({ startupState, isShutdownStarted, config }: CreateAppOptions) {
|
|
const app = express()
|
|
|
|
app.use(accessLogMiddleware)
|
|
app.use(createCorsMiddleware(config))
|
|
app.use(
|
|
express.json({
|
|
limit: '2mb',
|
|
verify: (req, _res, buffer) => {
|
|
;(req as Request).rawBody = buffer.toString('utf8')
|
|
},
|
|
}),
|
|
)
|
|
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,
|
|
mode: 'kuaishou-lite',
|
|
}),
|
|
)
|
|
})
|
|
|
|
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/open/affiliate-dash', affiliateDashRouter)
|
|
app.use('/api/v1/open/91', open91Router)
|
|
app.use('/api/v1/open/kuaishou-industry', kuaishouIndustryRouter)
|
|
app.use('/api/v1/open/kuaishou-feifei', kuaishouFeifeiRouter)
|
|
app.use('/api/v1/claim', claimsRouter)
|
|
app.use('/api/v1/collect', collectRouter)
|
|
app.use('/api/v1/files', filesRouter)
|
|
app.use('/api/v1/worker', workerRouter)
|
|
app.use('/api/v1/admin', adminRouter)
|
|
app.use('/s', shortLinksRouter)
|
|
|
|
app.use((err: unknown, _req: Request, res: Response, _next: NextFunction) => {
|
|
sendRouteError(res, err, '服务内部错误', '[global]')
|
|
})
|
|
|
|
return app
|
|
}
|