同步处理

This commit is contained in:
tianmo committed 2026-10-17 18:15:42 +08:00
1 parent 9939943e31
commit 6494ad2918
26 files changed
+970 -40

No files matched your search

@@ -0,0 +1,29 @@
import { requireSiteSyncAuth } from '../../utils/access'
import { createApiError } from '../../utils/api-error'
import { validateStorageKey } from '../../utils/image-key'
import { finalizeSiteSyncChunk } from '../../utils/site-sync/chunks'
interface Body {
jobId?: string
key?: string
}
export default defineEventHandler(async (event) => {
await requireSiteSyncAuth(event)
const body = await readBody<Body>(event).catch(() => null)
const jobId = body?.jobId?.trim() ?? ''
const key = body?.key?.trim() ?? ''
if (!jobId || !validateStorageKey(key)) {
createApiError(event, 'INVALID_REQUEST', '分块完成参数无效', 400)
}
try {
return await finalizeSiteSyncChunk({ jobId, key })
} catch (error) {
createApiError(
event,
'INVALID_REQUEST',
error instanceof Error ? error.message : '分块组装失败',
400
)
}
})
+16
View File
@@ -0,0 +1,16 @@
import { getQuery } from 'h3'
import { requireSiteSyncAuth } from '../../utils/access'
import { createApiError } from '../../utils/api-error'
import { validateStorageKey } from '../../utils/image-key'
import { getSiteSyncChunkStatus } from '../../utils/site-sync/chunks'
export default defineEventHandler(async (event) => {
await requireSiteSyncAuth(event)
const query = getQuery(event)
const jobId = typeof query.jobId === 'string' ? query.jobId.trim() : ''
const key = typeof query.key === 'string' ? query.key.trim() : ''
if (!jobId || !validateStorageKey(key)) {
createApiError(event, 'INVALID_REQUEST', '分块查询参数无效', 400)
}
return getSiteSyncChunkStatus({ jobId, key })
})
+54
View File
@@ -0,0 +1,54 @@
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
)
}
})
+3
View File
@@ -1,6 +1,7 @@
import { requireSiteSyncAuth } from '../../utils/access'
import { createApiError } from '../../utils/api-error'
import { cleanupSiteSyncJobArtifacts } from '../../utils/site-sync/artifacts'
import { cleanupSiteSyncChunkSessions } from '../../utils/site-sync/chunks'
interface Body {
jobId?: string
@@ -13,8 +14,10 @@ export default defineEventHandler(async (event) => {
if (!jobId || jobId.length > 128) {
createApiError(event, 'INVALID_REQUEST', '缺少同步任务 ID', 400)
}
const removedChunkSessions = await cleanupSiteSyncChunkSessions(jobId)
return {
success: true,
removedChunkSessions,
...await cleanupSiteSyncJobArtifacts(jobId)
}
})