Files
FileHost/server/api/site-sync/chunk.post.ts
T
2026-10-17 18:15:42 +08:00

55 lines
1.6 KiB
TypeScript

import { getHeader, readRawBody } from 'h3'
import { requireSiteSyncAuth } from '../../utils/access'
import { createApiError } from '../../utils/api-error'
import { validateStorageKey } from '../../utils/image-key'
import {
isSiteSyncChunkMetadata,
SITE_SYNC_CHUNK_SIZE,
writeSiteSyncChunk
} from '../../utils/site-sync/chunks'
export default defineEventHandler(async (event) => {
await requireSiteSyncAuth(event)
const encoded = getHeader(event, 'x-pichost-chunk-metadata') ?? ''
let metadata: unknown
try {
metadata = JSON.parse(Buffer.from(encoded, 'base64url').toString('utf8'))
} catch {
createApiError(event, 'INVALID_REQUEST', '分块元数据无效', 400)
}
if (
!isSiteSyncChunkMetadata(metadata)
|| !validateStorageKey(metadata.key)
|| !validateStorageKey(metadata.mediaKey)
) {
createApiError(event, 'INVALID_REQUEST', '分块元数据无效', 400)
}
const index = Number.parseInt(getHeader(event, 'x-pichost-chunk-index') ?? '', 10)
if (!Number.isInteger(index)) {
createApiError(event, 'INVALID_REQUEST', '分块序号无效', 400)
}
const body = await readRawBody(event, false)
if (!body?.length) {
createApiError(event, 'INVALID_REQUEST', '未收到分块数据', 400)
}
if (body.length > SITE_SYNC_CHUNK_SIZE) {
createApiError(event, 'FILE_TOO_LARGE', '分块超过 4 MB', 413)
}
try {
return await writeSiteSyncChunk({
metadata,
index,
bytes: new Uint8Array(body)
})
} catch (error) {
createApiError(
event,
'INVALID_REQUEST',
error instanceof Error ? error.message : '分块写入失败',
400
)
}
})