fenghuo/apps/web/hooks/useTusUpload.ts

123 lines
3.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState } from "react";
import * as tus from "tus-js-client";
import { env } from "../env";
import { getCompressedImageUrl } from "@nice/utils";
interface UploadResult {
compressedUrl: string;
url: string;
fileId: string;
fileName: string;
}
export function useTusUpload() {
const [uploadProgress, setUploadProgress] = useState<
Record<string, number>
>({});
const [isUploading, setIsUploading] = useState(false);
const [uploadError, setUploadError] = useState<string | null>(null);
const getFileId = (url: string) => {
const parts = url.split("/");
const uploadIndex = parts.findIndex((part) => part === "upload");
if (uploadIndex === -1 || uploadIndex + 4 >= parts.length) {
throw new Error("Invalid upload URL format");
}
return parts.slice(uploadIndex + 1, uploadIndex + 5).join("/");
};
const getResourceUrl = (url: string) => {
const parts = url.split("/");
const uploadIndex = parts.findIndex((part) => part === "upload");
if (uploadIndex === -1 || uploadIndex + 4 >= parts.length) {
throw new Error("Invalid upload URL format");
}
const resUrl = `http://${env.SERVER_IP}:${env.FILE_PORT}/uploads/${parts.slice(uploadIndex + 1, uploadIndex + 6).join("/")}`;
return resUrl;
};
const handleFileUpload = async (
file: File | Blob,
onSuccess: (result: UploadResult) => void,
onError: (error: Error) => void,
fileKey: string // 添加文件唯一标识
) => {
// console.log()
setIsUploading(true);
setUploadProgress((prev) => ({ ...prev, [fileKey]: 0 }));
setUploadError(null);
try {
// 如果是Blob需要转换为File
let fileName = "uploaded-file";
if (file instanceof Blob && !(file instanceof File)) {
// 根据MIME类型设置文件扩展名
const extension = file.type.split('/')[1];
fileName = `uploaded-file.${extension}`;
}
const uploadFile = file instanceof Blob && !(file instanceof File)
? new File([file], fileName, { type: file.type })
: file as File;
console.log(`http://${env.SERVER_IP}:${env.SERVER_PORT}/upload`);
const upload = new tus.Upload(uploadFile, {
endpoint: `http://${env.SERVER_IP}:${env.SERVER_PORT}/upload`,
retryDelays: [0, 1000, 3000, 5000],
metadata: {
filename: uploadFile.name,
filetype: uploadFile.type,
size: uploadFile.size as any,
},
onProgress: (bytesUploaded, bytesTotal) => {
const progress = Number(
((bytesUploaded / bytesTotal) * 100).toFixed(2)
);
setUploadProgress((prev) => ({
...prev,
[fileKey]: progress,
}));
},
onSuccess: async (payload) => {
if (upload.url) {
const fileId = getFileId(upload.url);
//console.log(fileId)
const url = getResourceUrl(upload.url);
setIsUploading(false);
setUploadProgress((prev) => ({
...prev,
[fileKey]: 100,
}));
onSuccess({
compressedUrl: getCompressedImageUrl(url),
url,
fileId,
fileName: uploadFile.name,
});
}
},
onError: (error) => {
const err =
error instanceof Error
? error
: new Error("Unknown error");
setIsUploading(false);
setUploadError(error.message);
console.log(error);
onError(err);
},
});
upload.start();
} catch (error) {
const err =
error instanceof Error ? error : new Error("Upload failed");
setIsUploading(false);
setUploadError(err.message);
onError(err);
}
};
return {
uploadProgress,
isUploading,
uploadError,
handleFileUpload,
};
}