Bỏ qua để đến nội dung chính

tus Protocol

tus is an open protocol for resumable file uploads. Use it for reliable uploads that can survive network interruptions.

Tại sao chọn tus?

  • Có thể tiếp tục: Tiếp tục tải lên sau lỗi mạng
  • Hiệu quả: Tiếp tục từ nơi bạn đã dừng, không phải từ đầu
  • Chuẩn hóa: Giao thức được định nghĩa rõ ràng với nhiều triển khai máy chủ
  • Phân mảnh: Tự động xử lý các tệp lớn

Cài đặt

npm install @samithahansaka/dropup tus-js-client

tus-js-client is a peer dependency.

Sử dụng Cơ bản

import { useDropup } from '@samithahansaka/dropup';
import { createTusUploader } from '@samithahansaka/dropup/tus';

function TusUploader() {
const { files, actions, state, getDropProps, getInputProps } = useDropup({
upload: createTusUploader({
endpoint: 'https://tusd.tusdemo.net/files/',
}),

onUploadComplete: (file) => {
console.log('Upload complete:', file.uploadedUrl);
},
});

return (
<div>
<div {...getDropProps()} style={styles.dropzone}>
<input {...getInputProps()} />
<p>Drop files for resumable upload</p>
</div>

{files.map(file => (
<div key={file.id} style={styles.fileItem}>
<span>{file.name}</span>
<span>{file.progress}%</span>
<span>{file.status}</span>
</div>
))}

<button onClick={() => actions.upload()}>
Upload
</button>
</div>
);
}

Tùy chọn Cấu hình

createTusUploader({
// Required
endpoint: 'https://your-tus-server.com/files/',

// Chunk size (default: Infinity = no chunking)
chunkSize: 5 * 1024 * 1024, // 5MB chunks

// Retry configuration
retryDelays: [0, 1000, 3000, 5000], // Retry after 0s, 1s, 3s, 5s

// Headers for all requests
headers: {
'Authorization': 'Bearer token',
},

// Metadata sent to server
metadata: {
filename: 'file.name',
filetype: 'file.type',
// Add custom metadata
userId: 'user123',
},

// Enable resumability via localStorage
storeFingerprintForResuming: true,

// Remove fingerprint after successful upload
removeFingerprintOnSuccess: true,

// Parallel uploads
parallelUploads: 3,
});

Resume Previous Uploads

tus can resume interrupted uploads:

const { files, actions } = useDropup({
upload: createTusUploader({
endpoint: 'https://your-tus-server.com/files/',

// Store upload URLs for resuming
storeFingerprintForResuming: true,

// Optional: custom storage key
urlStorageKey: 'my-app-tus-uploads',

onShouldRetry: (error, retryAttempt) => {
// Custom retry logic
if (error.message.includes('network')) {
return retryAttempt < 5;
}
return false;
},
}),
});

// Files can be resumed automatically when re-added
// or manually with retry:
actions.retry(['file-id']);

Progress Tracking

function TusWithProgress() {
const { files, actions, getDropProps, getInputProps } = useDropup({
upload: createTusUploader({
endpoint: 'https://your-tus-server.com/files/',
}),

onUploadProgress: (file, progress) => {
console.log(`${file.name}: ${progress}%`);
},

onUploadStart: (file) => {
console.log(`Starting upload: ${file.name}`);
},

onUploadComplete: (file) => {
console.log(`Complete: ${file.uploadedUrl}`);
},
});

return (
<div>
<div {...getDropProps()}>
<input {...getInputProps()} />
<p>Drop files here</p>
</div>

{files.map(file => (
<div key={file.id}>
<span>{file.name}</span>
{file.status === 'uploading' && (
<div style={styles.progressBar}>
<div
style={{
...styles.progress,
width: `${file.progress}%`,
}}
/>
</div>
)}
<span>{file.status}</span>
</div>
))}
</div>
);
}

Pause and Resume

function PausableUploader() {
const { files, actions, getDropProps, getInputProps } = useDropup({
upload: createTusUploader({
endpoint: 'https://your-tus-server.com/files/',
storeFingerprintForResuming: true,
}),
});

return (
<div>
<div {...getDropProps()}>
<input {...getInputProps()} />
<p>Drop files here</p>
</div>

{files.map(file => (
<div key={file.id}>
<span>{file.name}</span>
<span>{file.progress}%</span>

{file.status === 'uploading' && (
<button onClick={() => actions.cancel(file.id)}>
Pause
</button>
)}

{file.status === 'paused' && (
<button onClick={() => actions.retry([file.id])}>
Resume
</button>
)}

{file.status === 'error' && (
<button onClick={() => actions.retry([file.id])}>
Retry
</button>
)}
</div>
))}

<button onClick={() => actions.upload()}>
Start All
</button>
</div>
);
}

Server Setup

tusd (Official Server)

# Install tusd
go install github.com/tus/tusd/cmd/tusd@latest

# Run with default options
tusd -upload-dir=/uploads

# Run with S3 storage
tusd -s3-bucket=my-bucket -s3-endpoint=https://s3.amazonaws.com

Node.js (tus-node-server)

const { Server } = require('@tus/server');
const { FileStore } = require('@tus/file-store');

const server = new Server({
path: '/files',
datastore: new FileStore({ directory: './uploads' }),
});

// With Express
app.all('/files/*', server.handle.bind(server));

Custom Metadata Handling

// Server-side: access metadata
const server = new Server({
path: '/files',
datastore: new FileStore({ directory: './uploads' }),
onUploadCreate: async (req, res, upload) => {
// Access metadata sent from client
console.log(upload.metadata);
// { filename: 'photo.jpg', filetype: 'image/jpeg', userId: 'user123' }
},
onUploadFinish: async (req, res, upload) => {
// Process completed upload
console.log('Upload complete:', upload.id);
},
});

tus Extensions

Dropup's tus integration supports these tus extensions:

ExtensionDescription
CreationCreate new uploads
TerminationCancel uploads
ChecksumVerify integrity
ConcatenationParallel uploads
ExpirationAuto-cleanup

Error Handling

const { files, actions } = useDropup({
upload: createTusUploader({
endpoint: 'https://your-tus-server.com/files/',
retryDelays: [0, 1000, 3000, 5000, 10000],
}),

onUploadError: (file, error) => {
if (error.code === 'TUS_OFFLINE') {
console.log('Network offline, will resume when connected');
} else if (error.code === 'TUS_EXPIRED') {
console.log('Upload expired, starting fresh');
actions.retry([file.id]);
} else {
console.error('Upload failed:', error.message);
}
},
});

Large File Uploads

tus is ideal for large files:

function LargeFileUploader() {
const { files, actions, getDropProps, getInputProps } = useDropup({
maxSize: 10 * 1024 * 1024 * 1024, // 10GB limit

upload: createTusUploader({
endpoint: 'https://your-tus-server.com/files/',
chunkSize: 50 * 1024 * 1024, // 50MB chunks
retryDelays: [0, 3000, 5000, 10000, 20000],
storeFingerprintForResuming: true,
}),

onUploadProgress: (file, progress) => {
// Show detailed progress for large files
const uploadedMB = (file.size * progress / 100 / 1024 / 1024).toFixed(0);
const totalMB = (file.size / 1024 / 1024).toFixed(0);
console.log(`${uploadedMB}MB / ${totalMB}MB`);
},
});

return (
<div {...getDropProps()}>
<input {...getInputProps()} />
<p>Upload large files (up to 10GB)</p>
</div>
);
}

Comparison: tus vs Chunked Upload

FeaturetusCustom Chunked
ResumabilityBuilt-inManual
Server supportMany optionsCustom
Protocol overheadHigherLower
ConfigurationStandardizedFlexible
Best forLarge files, unreliable networksSimple uploads