106 lines
4.5 KiB
JavaScript
106 lines
4.5 KiB
JavaScript
import { createRequestError } from './request-client.js'
|
|
import { normalizeOptionalResponseText } from './response-normalizers.js'
|
|
import { assertPlainPayload, normalizeOptionalText } from './request-normalizers.js'
|
|
|
|
const normalizeFileResponseText = (value, field) =>
|
|
normalizeOptionalResponseText(value, field, '文件服务响应', 'FILE_RESPONSE_INVALID')
|
|
|
|
export const normalizeUploadId = (value, field) => {
|
|
if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${field}必须是非空字符串`)
|
|
return value.trim()
|
|
}
|
|
|
|
const normalizeUploadFileName = (value) => {
|
|
if (typeof value !== 'string' || !value.trim()) throw new TypeError('fileName必须是非空字符串')
|
|
return value.trim()
|
|
}
|
|
|
|
export const normalizeUploadMd5 = (value, field) => {
|
|
if (typeof value !== 'string' || !/^[a-f0-9]{32}$/i.test(value)) {
|
|
throw new TypeError(`${field}必须是 32 位十六进制 MD5`)
|
|
}
|
|
return value.toLowerCase()
|
|
}
|
|
|
|
const normalizeUploadSize = (value, field) => {
|
|
if (!Number.isSafeInteger(value) || value <= 0) throw new TypeError(`${field}必须是正安全整数`)
|
|
return value
|
|
}
|
|
|
|
export const normalizeResumableInitPayload = (payload) => {
|
|
const allowedFields = new Set(['uploadId', 'fileName', 'fileMd5', 'totalSize', 'totalChunks', 'chunkSize', 'contentType'])
|
|
assertPlainPayload(payload, allowedFields, '文件初始化请求')
|
|
if (!Number.isInteger(payload.totalChunks) || payload.totalChunks <= 0 || payload.totalChunks > 2147483647) {
|
|
throw new TypeError('totalChunks必须是正 int32')
|
|
}
|
|
const normalizedPayload = {
|
|
uploadId: normalizeUploadId(payload.uploadId, 'uploadId'),
|
|
fileName: normalizeUploadFileName(payload.fileName),
|
|
fileMd5: normalizeUploadMd5(payload.fileMd5, 'fileMd5'),
|
|
totalSize: normalizeUploadSize(payload.totalSize, 'totalSize'),
|
|
totalChunks: payload.totalChunks,
|
|
chunkSize: normalizeUploadSize(payload.chunkSize, 'chunkSize')
|
|
}
|
|
const contentType = normalizeOptionalText(payload.contentType, 'contentType')
|
|
if (contentType) normalizedPayload.contentType = contentType
|
|
return normalizedPayload
|
|
}
|
|
|
|
export const normalizeResumableCompletePayload = (payload) => {
|
|
const allowedFields = new Set(['uploadId', 'fileName', 'fileMd5', 'totalSize', 'totalChunks'])
|
|
assertPlainPayload(payload, allowedFields, '文件完成请求')
|
|
if (!Number.isInteger(payload.totalChunks) || payload.totalChunks <= 0 || payload.totalChunks > 2147483647) {
|
|
throw new TypeError('totalChunks必须是正 int32')
|
|
}
|
|
return {
|
|
uploadId: normalizeUploadId(payload.uploadId, 'uploadId'),
|
|
fileName: normalizeUploadFileName(payload.fileName),
|
|
fileMd5: normalizeUploadMd5(payload.fileMd5, 'fileMd5'),
|
|
totalSize: normalizeUploadSize(payload.totalSize, 'totalSize'),
|
|
totalChunks: payload.totalChunks
|
|
}
|
|
}
|
|
|
|
const normalizeUploadOssId = (value, field) => {
|
|
const id = typeof value === 'number' && Number.isSafeInteger(value) ? String(value) : value
|
|
if (typeof id !== 'string' || !/^[1-9]\d*$/.test(id)) {
|
|
throw createRequestError(`文件服务字段 ${field} 无效`, 'FILE_RESPONSE_INVALID')
|
|
}
|
|
return id
|
|
}
|
|
|
|
export const normalizeResumableInitResult = (payload) => {
|
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
throw createRequestError('文件初始化响应格式无效', 'FILE_RESPONSE_INVALID')
|
|
}
|
|
if (typeof payload.instant !== 'boolean') {
|
|
throw createRequestError('文件初始化响应缺少 instant', 'FILE_RESPONSE_INVALID')
|
|
}
|
|
const ossId = payload.ossId === undefined || payload.ossId === null ? null : normalizeUploadOssId(payload.ossId, 'ossId')
|
|
if (payload.instant && !ossId) {
|
|
throw createRequestError('秒传响应缺少 ossId', 'FILE_RESPONSE_INVALID')
|
|
}
|
|
const uploadId = payload.instant && (payload.uploadId === undefined || payload.uploadId === null)
|
|
? null
|
|
: normalizeUploadId(payload.uploadId, '响应 uploadId')
|
|
return {
|
|
uploadId,
|
|
instant: payload.instant,
|
|
ossId,
|
|
url: normalizeFileResponseText(payload.url, 'url'),
|
|
fileName: normalizeFileResponseText(payload.fileName, 'fileName')
|
|
}
|
|
}
|
|
|
|
export const normalizeResumableCompleteResult = (payload) => {
|
|
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
throw createRequestError('文件完成响应格式无效', 'FILE_RESPONSE_INVALID')
|
|
}
|
|
return {
|
|
ossId: normalizeUploadOssId(payload.ossId, 'ossId'),
|
|
url: normalizeFileResponseText(payload.url, 'url'),
|
|
thumbnailUrl: normalizeFileResponseText(payload.thumbnailUrl, 'thumbnailUrl'),
|
|
fileName: normalizeFileResponseText(payload.fileName, 'fileName')
|
|
}
|
|
}
|