A modern, serverless file-sharing application built on Cloudflare Workers that prioritizes direct peer-to-peer (P2P) transfers with automatic cloud storage fallback.
- P2P First: Direct browser-to-browser file transfer using WebRTC DataChannels
- Automatic Fallback: Seamlessly falls back to R2 cloud storage if P2P fails
- No Server Storage: Files transferred P2P never touch the server
- Real-time Signaling: WebSocket-based signaling via Cloudflare Durable Objects
- Simple Room Codes: 6-character codes for easy peer connection
- Progress Tracking: Real-time transfer progress for both sender and receiver
- Modern UI: Clean, responsive interface with status indicators
βββββββββββββββ βββββββββββββββ
β Sender β β Receiver β
β Browser β β Browser β
ββββββββ¬βββββββ ββββββββ¬βββββββ
β β
β ββββββββββββββββββββββββββββββ β
ββββ€ WebSocket Signaling βββ
β (Durable Object) β
β - Offer/Answer Exchange β
β - ICE Candidates β
ββββββββββββββββββββββββββββββ
β β
β ββββββββββββββββββββββββββββββ β
ββββ€ WebRTC P2P Connection βββ
β (DataChannel) β
β - Direct file transfer β
β - No server intermediary β
ββββββββββββββββββββββββββββββ
β β
β ββββββββββββββββββββββββββββββ β
ββββ€ R2 Fallback (if P2P fails)βββ
β - Upload to R2 β
β - Download link via WS β
ββββββββββββββββββββββββββββββ
-
Cloudflare Worker (
worker.js)- Serves the HTML/CSS/JS UI
- Handles WebSocket upgrade requests
- Manages R2 upload/download endpoints
-
Durable Object (
SignalingRoom)- One instance per room code
- Manages WebSocket connections
- Routes WebRTC signaling messages between peers
- Handles peer join/leave events
-
R2 Bucket (
swiftdrop-files)- Fallback storage for files when P2P fails
- 24-hour expiration on stored files
- Metadata tracking (uploader, timestamp, filename)
-
Client-Side Logic
- WebRTC PeerConnection management
- DataChannel file transfer with chunking
- Automatic fallback detection and handling
- Progress tracking and UI updates
- Node.js 16+ installed
- Cloudflare account
- Wrangler CLI installed:
npm install -g wrangler - Authenticated with Wrangler:
wrangler login
# Create the R2 bucket
wrangler r2 bucket create swiftdrop-files
# Verify it was created
wrangler r2 bucket list# Deploy to Cloudflare
wrangler deploy
# You'll see output like:
# Published swiftdrop (X.XX sec)
# https://swiftdrop.your-subdomain.workers.dev- Open the deployed URL in two browser windows/tabs
- Window 1 (Sender):
- A 6-digit room code is automatically generated
- Click to select a file
- Wait for receiver to join
- Window 2 (Receiver):
- Click "π₯ Receive File"
- Enter the room code from Window 1
- Click "Join Room"
- Transfer begins automatically (P2P if possible, fallback if needed)
In worker.js, you can adjust the P2P connection timeout:
const CONFIG = {
p2pTimeout: 5000, // 5 seconds (default)
chunkSize: 16384 // 16KB chunks
};Files stored in R2 expire after 24 hours by default. Modify in the upload handler:
expiresAt: (timestamp + 24 * 60 * 60 * 1000).toString() // 24 hoursThe default STUN servers are Google's public servers. You can add your own:
const CONFIG = {
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'stun:your-stun-server.com:3478' }
]
};Serves the HTML UI
WebSocket endpoint for signaling
- Upgrades to WebSocket
- Routes to appropriate Durable Object instance
- Manages peer connections
Fallback upload endpoint
- Content-Type:
multipart/form-data - Body:
file: File blobroomCode: 6-character room codefileName: Original filename
- Response:
{ success: true, fileId: "...", downloadUrl: "/download/..." }
Fallback download endpoint
- Streams file from R2
- Sets proper Content-Disposition headers
- Checks expiration and deletes expired files
- Sender generates room code, connects to signaling server
- Receiver enters room code, connects to same signaling server
- Signaling server notifies both peers of each other's presence
- Sender creates WebRTC PeerConnection and DataChannel
- Sender generates SDP offer, sends via signaling server
- Receiver receives offer, creates answer, sends back
- Both exchange ICE candidates for NAT traversal
- DataChannel opens (if successful within 5 seconds)
- Sender sends file metadata, then chunks over DataChannel
- Receiver receives chunks, reassembles file, triggers download
- P2P connection timeout (5 seconds) expires
- Sender uploads file to R2 via
/uploadendpoint - Sender sends download link to receiver via signaling
- Receiver shows download button with link to
/download/:fileId - Receiver clicks download, file streams from R2
# Start local development server
wrangler dev
# Access at http://localhost:8787Note: Local testing with two separate browsers is tricky. For full testing:
- Deploy to Cloudflare
- Use the deployed URL for testing
- Or use
wrangler dev --remotefor remote development mode
# Tail production logs
wrangler tail
# View specific deployment logs
wrangler tail --format jsonEnable detailed logging in the worker:
// In SignalingRoom class
console.log(`[Room] Message type: ${data.type}`);
console.log(`[Room] Peer count: ${this.sessions.size}`);-
Room Codes: Currently 6 characters (~2 billion combinations)
- Consider increasing length for production
- Add rate limiting on room creation
-
File Size Limits: No server-side limits currently enforced
- Add max file size validation
- Consider Worker memory limits (~128MB)
-
R2 Expiration: Files expire after 24 hours
- Consider implementing cleanup worker
- Add lifecycle policies to R2 bucket
-
CORS: Currently allows all origins
- Restrict to your domain in production
- P2P Transfer: Limited only by peer bandwidth and browser memory
- Fallback Upload: Limited by Cloudflare Worker limits
- Max request size: 100MB (Workers Free), 500MB (Workers Paid)
- Consider chunked uploads for very large files
- Concurrent Connections: Durable Objects can handle thousands of WebSocket connections
- Check browser console for WebRTC errors
- Verify STUN servers are accessible
- Test from different networks (corporate firewalls may block WebRTC)
- Try different browsers (Chrome, Firefox have best WebRTC support)
- Verify R2 bucket exists:
wrangler r2 bucket list - Check Worker logs:
wrangler tail - Verify binding name matches
wrangler.toml
- Check Durable Object is deployed:
wrangler deployments list - Verify migration ran successfully
- Check for CORS issues in browser console
MIT License - feel free to use for personal or commercial projects
Contributions welcome! Areas for improvement:
- Add file encryption for P2P transfers
- Implement resumable uploads for fallback
- Add progress indicators for multi-file transfers
- Create admin panel for R2 cleanup
- Add authentication/authorization
- Implement rate limiting
- Add telemetry and analytics
- Mobile app using same backend
Built with:
Inspired by: