151 lines
4.0 KiB
TypeScript
151 lines
4.0 KiB
TypeScript
|
|
/**
|
||
|
|
* Upload API for file uploads via proxy to MinIO
|
||
|
|
* Supports both Web and Native platforms
|
||
|
|
*/
|
||
|
|
import { Platform } from "react-native"
|
||
|
|
|
||
|
|
const OSS_BASE_URL = "https://oss.upay01.com"
|
||
|
|
|
||
|
|
// Upload response type
|
||
|
|
export interface UploadResponse {
|
||
|
|
code: number
|
||
|
|
message: string
|
||
|
|
data?: {
|
||
|
|
filename: string
|
||
|
|
originalName: string
|
||
|
|
size: number
|
||
|
|
mimetype: string
|
||
|
|
url: string
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Convert a URI to Blob (for Web platform)
|
||
|
|
*/
|
||
|
|
async function uriToBlob(uri: string): Promise<Blob> {
|
||
|
|
const response = await fetch(uri)
|
||
|
|
const blob = await response.blob()
|
||
|
|
return blob
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Upload file on Web platform
|
||
|
|
*/
|
||
|
|
async function uploadFileWeb(
|
||
|
|
uri: string,
|
||
|
|
fileName: string,
|
||
|
|
mimeType: string,
|
||
|
|
): Promise<{ kind: "ok"; url: string } | { kind: "error"; message: string }> {
|
||
|
|
try {
|
||
|
|
// Convert URI to Blob for Web
|
||
|
|
const blob = await uriToBlob(uri)
|
||
|
|
const file = new File([blob], fileName, { type: mimeType })
|
||
|
|
|
||
|
|
const formData = new FormData()
|
||
|
|
formData.append("file", file)
|
||
|
|
|
||
|
|
const response = await fetch(`${OSS_BASE_URL}/api/proxy/upload`, {
|
||
|
|
method: "POST",
|
||
|
|
body: formData,
|
||
|
|
})
|
||
|
|
|
||
|
|
const data: UploadResponse = await response.json()
|
||
|
|
|
||
|
|
if (response.ok && data.code === 200 && data.data?.url) {
|
||
|
|
return { kind: "ok", url: data.data.url }
|
||
|
|
} else {
|
||
|
|
return { kind: "error", message: data.message || "Upload failed" }
|
||
|
|
}
|
||
|
|
} catch (e) {
|
||
|
|
if (__DEV__ && e instanceof Error) {
|
||
|
|
console.error(`Upload error: ${e.message}`)
|
||
|
|
}
|
||
|
|
return { kind: "error", message: "Upload failed" }
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Upload file on Native platform (iOS/Android)
|
||
|
|
*/
|
||
|
|
function uploadFileNative(
|
||
|
|
uri: string,
|
||
|
|
fileName: string,
|
||
|
|
mimeType: string,
|
||
|
|
): Promise<{ kind: "ok"; url: string } | { kind: "error"; message: string }> {
|
||
|
|
return new Promise((resolve) => {
|
||
|
|
try {
|
||
|
|
const xhr = new XMLHttpRequest()
|
||
|
|
|
||
|
|
xhr.onload = () => {
|
||
|
|
if (__DEV__) {
|
||
|
|
console.log("Upload response status:", xhr.status)
|
||
|
|
console.log("Upload response body:", xhr.responseText)
|
||
|
|
}
|
||
|
|
if (xhr.status === 200) {
|
||
|
|
try {
|
||
|
|
const response: UploadResponse = JSON.parse(xhr.responseText)
|
||
|
|
if (response.code === 200 && response.data?.url) {
|
||
|
|
resolve({ kind: "ok", url: response.data.url })
|
||
|
|
} else {
|
||
|
|
resolve({ kind: "error", message: response.message || "Upload failed" })
|
||
|
|
}
|
||
|
|
} catch {
|
||
|
|
resolve({ kind: "error", message: "Invalid response" })
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (__DEV__) {
|
||
|
|
console.log("Upload failed - Status:", xhr.status, "Response:", xhr.responseText)
|
||
|
|
}
|
||
|
|
resolve({ kind: "error", message: `Upload failed with status ${xhr.status}` })
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
xhr.onerror = () => {
|
||
|
|
resolve({ kind: "error", message: "Network error" })
|
||
|
|
}
|
||
|
|
|
||
|
|
xhr.ontimeout = () => {
|
||
|
|
resolve({ kind: "error", message: "Upload timeout" })
|
||
|
|
}
|
||
|
|
|
||
|
|
xhr.open("POST", `${OSS_BASE_URL}/api/proxy/upload`)
|
||
|
|
xhr.timeout = 60000
|
||
|
|
|
||
|
|
// React Native specific FormData format
|
||
|
|
const formData = new FormData()
|
||
|
|
formData.append("file", {
|
||
|
|
uri: uri,
|
||
|
|
type: mimeType,
|
||
|
|
name: fileName,
|
||
|
|
} as any)
|
||
|
|
|
||
|
|
xhr.send(formData)
|
||
|
|
} catch (e) {
|
||
|
|
if (__DEV__ && e instanceof Error) {
|
||
|
|
console.error(`Upload error: ${e.message}`)
|
||
|
|
}
|
||
|
|
resolve({ kind: "error", message: "Upload failed" })
|
||
|
|
}
|
||
|
|
})
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Upload a file to OSS storage
|
||
|
|
* Automatically handles Web vs Native platform differences
|
||
|
|
* @param uri - Local file URI
|
||
|
|
* @param fileName - File name
|
||
|
|
* @param mimeType - MIME type of the file
|
||
|
|
* @returns Upload result with URL or error
|
||
|
|
*/
|
||
|
|
export async function uploadFile(
|
||
|
|
uri: string,
|
||
|
|
fileName: string,
|
||
|
|
mimeType: string,
|
||
|
|
): Promise<{ kind: "ok"; url: string } | { kind: "error"; message: string }> {
|
||
|
|
if (Platform.OS === "web") {
|
||
|
|
return uploadFileWeb(uri, fileName, mimeType)
|
||
|
|
} else {
|
||
|
|
return uploadFileNative(uri, fileName, mimeType)
|
||
|
|
}
|
||
|
|
}
|