forked from 77media/video-flow
156 lines
4.5 KiB
TypeScript
156 lines
4.5 KiB
TypeScript
// Common API 相关接口
|
||
import { BASE_URL } from './constants'
|
||
|
||
export interface ApiResponse<T = any> {
|
||
code: number
|
||
successful: boolean
|
||
message: string
|
||
data: T
|
||
}
|
||
|
||
export interface TokenResponse {
|
||
code: number
|
||
message: string
|
||
data: {
|
||
token: string
|
||
}
|
||
successful: boolean
|
||
}
|
||
|
||
export interface TokenWithDomainResponse {
|
||
code: number
|
||
message: string
|
||
data: {
|
||
token: string
|
||
domain: string
|
||
}
|
||
successful: boolean
|
||
}
|
||
|
||
export interface QiniuUploadResponse {
|
||
hash: string
|
||
key: string
|
||
url?: string
|
||
}
|
||
|
||
|
||
// 获取七牛云上传token(包含domain)
|
||
export const getUploadToken = async (timeoutMs: number = 10000): Promise<{ token: string, domain: string }> => {
|
||
// 添加超时控制
|
||
const controller = new AbortController()
|
||
const timeoutId = setTimeout(() => {
|
||
console.log(`Request timeout(${timeoutMs / 1000}s),aborting...`)
|
||
controller.abort()
|
||
}, timeoutMs)
|
||
|
||
try {
|
||
const response = await fetch(`${BASE_URL}/common/get-upload-token`, {
|
||
method: "GET",
|
||
headers: {
|
||
Accept: "application/json",
|
||
"Content-Type": "application/json",
|
||
},
|
||
signal: controller.signal,
|
||
mode: "cors",
|
||
})
|
||
|
||
// 请求完成后清除超时
|
||
clearTimeout(timeoutId)
|
||
|
||
if (!response.ok) {
|
||
const errorText = await response.text()
|
||
console.error("Get token response error:", response.status, errorText)
|
||
throw new Error(`Get token failed: ${response.status} ${response.statusText}`)
|
||
}
|
||
|
||
const result: TokenWithDomainResponse | TokenResponse = await response.json()
|
||
console.log("Get token response:", result)
|
||
|
||
if (result.code === 0 && result.successful && result.data.token) {
|
||
console.log("Successfully get token")
|
||
// Support both old and new API response formats
|
||
const domain = 'domain' in result.data ? result.data.domain : 'cdn.qikongjian.com'
|
||
return {
|
||
token: result.data.token,
|
||
domain: domain
|
||
}
|
||
} else {
|
||
throw new Error(result.message || "Get token failed, server did not return a valid token")
|
||
}
|
||
} catch (error) {
|
||
clearTimeout(timeoutId)
|
||
console.error("Get upload token failed:", error)
|
||
|
||
if (error instanceof Error) {
|
||
if (error.name === "AbortError") {
|
||
throw new Error("Request timeout, please check your network connection")
|
||
} else if (error.message.includes("Failed to fetch")) {
|
||
throw new Error("Network connection failed, possibly due to CORS policy or server unreachable")
|
||
}
|
||
}
|
||
|
||
throw error
|
||
}
|
||
}
|
||
|
||
// 生成唯一文件名
|
||
export const generateUniqueFileName = (originalName: string): string => {
|
||
const timestamp = Date.now()
|
||
const randomStr = Math.random().toString(36).substring(2, 8)
|
||
const extension = originalName.split(".").pop()
|
||
return `videos/${timestamp}_${randomStr}.${extension}`
|
||
}
|
||
|
||
// 七牛云上传
|
||
export const uploadToQiniu = async (
|
||
file: File,
|
||
token: string,
|
||
onProgress?: (progress: number) => void
|
||
): Promise<string> => {
|
||
const uniqueFileName = generateUniqueFileName(file.name)
|
||
|
||
const formData = new FormData()
|
||
formData.append("token", token)
|
||
formData.append("key", uniqueFileName)
|
||
formData.append("file", file)
|
||
|
||
return new Promise((resolve, reject) => {
|
||
const xhr = new XMLHttpRequest()
|
||
|
||
xhr.upload.addEventListener("progress", (event) => {
|
||
if (event.lengthComputable && onProgress) {
|
||
const progress = Math.round((event.loaded / event.total) * 100)
|
||
onProgress(progress)
|
||
}
|
||
})
|
||
|
||
xhr.addEventListener("load", () => {
|
||
if (xhr.status >= 200 && xhr.status < 300) {
|
||
try {
|
||
const response: QiniuUploadResponse = JSON.parse(xhr.responseText)
|
||
const qiniuUrl = `https://cdn.qikongjian.com/${response.key || uniqueFileName}`
|
||
console.log("Qiniu cloud upload success:", response)
|
||
resolve(qiniuUrl)
|
||
} catch (error) {
|
||
console.error("Parse response failed:", error, "Original response:", xhr.responseText)
|
||
reject(new Error(`Parse upload response failed: ${xhr.responseText}`))
|
||
}
|
||
} else {
|
||
console.error("Qiniu cloud upload failed:", xhr.status, xhr.statusText, xhr.responseText)
|
||
reject(new Error(`Upload failed: ${xhr.status} ${xhr.statusText}`))
|
||
}
|
||
})
|
||
|
||
xhr.addEventListener("error", (e) => {
|
||
console.error("Upload network error:", e)
|
||
reject(new Error("Network error, upload failed"))
|
||
})
|
||
|
||
xhr.addEventListener("abort", () => {
|
||
reject(new Error("Upload aborted"))
|
||
})
|
||
|
||
xhr.open("POST", "https://up-z2.qiniup.com")
|
||
xhr.send(formData)
|
||
})
|
||
}
|