72 lines
2.2 KiB
TypeScript
72 lines
2.2 KiB
TypeScript
import { defineEventHandler, getRouterParam } from 'h3'
|
|
import { eq, desc } from 'drizzle-orm'
|
|
import { db } from '~/drizzle/db'
|
|
import { backupHistory } from '~/drizzle/schema'
|
|
import { createApiError } from '~~/server/utils/apiError'
|
|
import { SERVER_ERROR_CODES } from '~~/server/config/constants'
|
|
|
|
/** 60 秒超时阈值 */
|
|
const TIMEOUT_THRESHOLD_MS = 60_000
|
|
|
|
export default defineEventHandler(async (event) => {
|
|
const idParam = getRouterParam(event, 'id')
|
|
|
|
if (!idParam) {
|
|
throw createApiError(400, SERVER_ERROR_CODES.COMMON_INVALID_PARAMS, '缺少备份 ID')
|
|
}
|
|
|
|
let record
|
|
|
|
if (idParam === 'latest') {
|
|
const [latest] = await db
|
|
.select()
|
|
.from(backupHistory)
|
|
.orderBy(desc(backupHistory.createdAt))
|
|
.limit(1)
|
|
record = latest
|
|
} else {
|
|
const backupId = parseInt(idParam, 10)
|
|
if (isNaN(backupId)) {
|
|
throw createApiError(400, SERVER_ERROR_CODES.COMMON_INVALID_PARAMS, '无效的备份 ID')
|
|
}
|
|
const [found] = await db
|
|
.select()
|
|
.from(backupHistory)
|
|
.where(eq(backupHistory.id, backupId))
|
|
record = found
|
|
}
|
|
|
|
if (!record) {
|
|
throw createApiError(404, 'BACKUP_NOT_FOUND', '备份记录不存在')
|
|
}
|
|
|
|
const methods: Array<{ method: string; success: boolean; error?: string | null }> = JSON.parse(record.methods)
|
|
const allCompleted = methods.every(m => m.success || m.error != null)
|
|
const age = Date.now() - new Date(record.createdAt).getTime()
|
|
const completedCount = methods.filter(m => m.success || m.error != null).length
|
|
const succeededCount = methods.filter(m => m.success).length
|
|
const failedCount = methods.filter(m => m.error != null).length
|
|
|
|
const status = allCompleted
|
|
? (succeededCount === methods.length ? 'completed' : failedCount === methods.length ? 'failed' : 'partial')
|
|
: (age > TIMEOUT_THRESHOLD_MS ? 'timeout' : 'running')
|
|
|
|
return {
|
|
success: true,
|
|
data: {
|
|
id: record.id,
|
|
filename: record.filename,
|
|
status,
|
|
totalRecords: record.totalRecords,
|
|
backupSize: record.backupSize,
|
|
createdAt: record.createdAt,
|
|
progress: {
|
|
total: methods.length,
|
|
completed: completedCount,
|
|
succeeded: succeededCount,
|
|
failed: failedCount
|
|
},
|
|
methods
|
|
}
|
|
}
|
|
}) |