feat: implement dynamic upload timeout based on file size across components (#246)

This commit is contained in:
Daniel Luiz Alves
2025-09-09 10:40:01 -03:00
committed by GitHub
3 changed files with 48 additions and 2 deletions

View File

@@ -150,6 +150,18 @@ export function FileUploadSection({ reverseShare, password, alias, onUploadSucce
return fileName.split(".").pop() || ""; return fileName.split(".").pop() || "";
}; };
const calculateUploadTimeout = (fileSize: number): number => {
const baseTimeout = 300000;
const fileSizeMB = fileSize / (1024 * 1024);
if (fileSizeMB > 500) {
const extraMB = fileSizeMB - 500;
const extraMinutes = Math.ceil(extraMB / 100);
return baseTimeout + extraMinutes * 60000;
}
return baseTimeout;
};
const uploadFileToStorage = async ( const uploadFileToStorage = async (
file: File, file: File,
presignedUrl: string, presignedUrl: string,
@@ -172,10 +184,14 @@ export function FileUploadSection({ reverseShare, password, alias, onUploadSucce
throw new Error(result.error || "Chunked upload failed"); throw new Error(result.error || "Chunked upload failed");
} }
} else { } else {
const uploadTimeout = calculateUploadTimeout(file.size);
await axios.put(presignedUrl, file, { await axios.put(presignedUrl, file, {
headers: { headers: {
"Content-Type": file.type, "Content-Type": file.type,
}, },
timeout: uploadTimeout,
maxContentLength: Infinity,
maxBodyLength: Infinity,
onUploadProgress: (progressEvent) => { onUploadProgress: (progressEvent) => {
if (onProgress && progressEvent.total) { if (onProgress && progressEvent.total) {
const progress = (progressEvent.loaded / progressEvent.total) * 100; const progress = (progressEvent.loaded / progressEvent.total) * 100;

View File

@@ -64,6 +64,18 @@ export function GlobalDropZone({ onSuccess, children, currentFolderId }: GlobalD
[generateFileId] [generateFileId]
); );
const calculateUploadTimeout = useCallback((fileSize: number): number => {
const baseTimeout = 300000;
const fileSizeMB = fileSize / (1024 * 1024);
if (fileSizeMB > 500) {
const extraMB = fileSizeMB - 500;
const extraMinutes = Math.ceil(extraMB / 100);
return baseTimeout + extraMinutes * 60000;
}
return baseTimeout;
}, []);
const handleDragOver = useCallback((event: DragEvent) => { const handleDragOver = useCallback((event: DragEvent) => {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();
@@ -158,11 +170,16 @@ export function GlobalDropZone({ onSuccess, children, currentFolderId }: GlobalD
folderId: currentFolderId, folderId: currentFolderId,
}); });
} else { } else {
const uploadTimeout = calculateUploadTimeout(file.size);
await axios.put(url, file, { await axios.put(url, file, {
headers: { headers: {
"Content-Type": file.type, "Content-Type": file.type,
}, },
signal: abortController.signal, signal: abortController.signal,
timeout: uploadTimeout, // Dynamic timeout based on file size
maxContentLength: Infinity,
maxBodyLength: Infinity,
onUploadProgress: (progressEvent: any) => { onUploadProgress: (progressEvent: any) => {
const progress = (progressEvent.loaded / (progressEvent.total || file.size)) * 100; const progress = (progressEvent.loaded / (progressEvent.total || file.size)) * 100;
setFileUploads((prev) => prev.map((u) => (u.id === id ? { ...u, progress: Math.round(progress) } : u))); setFileUploads((prev) => prev.map((u) => (u.id === id ? { ...u, progress: Math.round(progress) } : u)));
@@ -203,7 +220,7 @@ export function GlobalDropZone({ onSuccess, children, currentFolderId }: GlobalD
); );
} }
}, },
[t, isS3Enabled, currentFolderId] [t, isS3Enabled, currentFolderId, calculateUploadTimeout]
); );
const handleDrop = useCallback( const handleDrop = useCallback(

View File

@@ -231,6 +231,18 @@ export function UploadFileModal({ isOpen, onClose, onSuccess, currentFolderId }:
); );
}; };
const calculateUploadTimeout = (fileSize: number): number => {
const baseTimeout = 300000;
const fileSizeMB = fileSize / (1024 * 1024);
if (fileSizeMB > 500) {
const extraMB = fileSizeMB - 500;
const extraMinutes = Math.ceil(extraMB / 100);
return baseTimeout + extraMinutes * 60000;
}
return baseTimeout;
};
const uploadFile = async (fileUpload: FileUpload) => { const uploadFile = async (fileUpload: FileUpload) => {
const { file, id } = fileUpload; const { file, id } = fileUpload;
@@ -312,12 +324,13 @@ export function UploadFileModal({ isOpen, onClose, onSuccess, currentFolderId }:
folderId: currentFolderId, folderId: currentFolderId,
}); });
} else { } else {
const uploadTimeout = calculateUploadTimeout(file.size);
await axios.put(url, file, { await axios.put(url, file, {
headers: { headers: {
"Content-Type": file.type, "Content-Type": file.type,
}, },
signal: abortController.signal, signal: abortController.signal,
timeout: 300000, // 5 minutes timeout for direct uploads timeout: uploadTimeout,
maxContentLength: Infinity, maxContentLength: Infinity,
maxBodyLength: Infinity, maxBodyLength: Infinity,
onUploadProgress: (progressEvent) => { onUploadProgress: (progressEvent) => {