Introduction
In today’s digital world, real-time file sharing has become essential. Services like AirDrop allow seamless peer-to-peer transfers, but implementing such a system over the web requires careful design choices. In this blog, I will walk you through my approach to building a real-time, WebSocket-based file-sharing system that supports compressed file transfers using Pako.js.
This project enables users to join a room, discover peers, and exchange files efficiently over WebSockets. The added advantage of Pako compression reduces network bandwidth usage, making transfers faster and more efficient.
Deployed URL-: https://intrashare.abhilaksharora.com/
Project Architecture & Tech Stack
Frontend:
- Next.js – For a modern and scalable frontend.
- Tailwind CSS – For styling.
- Pako.js – To handle file compression and decompression.
- WebSockets – For real-time communication.
Backend:
- Node.js – Server-side JavaScript runtime.
- WebSocket Server (ws package) – To manage real-time connections and room-based messaging.
- Express.js (Optional) – If we extend it with REST APIs.
Frontend Implementation
1. Establishing a WebSocket Connection
We need to initialize a WebSocket connection that allows users to join a room and communicate.
Extracting Room Code from URL
useEffect(() => { if (typeof window !== "undefined") { const params = new URLSearchParams(window.location.search); const roomCodeFromURL = params.get("roomCode"); if (roomCodeFromURL) setRoomCode(roomCodeFromURL); } }, []);
This extracts the roomCode
parameter from the URL (e.g., ?roomCode=ABCDE
) and updates the state.
Joining a WebSocket Room
const joinRoom = (roomCode: string) => { if (!roomCode.trim()) { alert("Please enter a room code!"); return; } if (myNameRef.current === "") { const name = randomName(); setMyName(name); myNameRef.current = name; } const socket = new WebSocket("wss://file-transfer-server.com"); setWs(socket); socket.onopen = () => { socket.send(JSON.stringify({ type: "join_room", roomCode, name: myNameRef.current })); }; socket.onmessage = (event) => { const data = JSON.parse(event.data); if (data.type === "room_update") { setUsersInRoom(data.users.filter((user) => user !== myNameRef.current)); } }; };
This function:
- Validates the room code.
- Generates a random user name if none exists.
- Establishes a WebSocket connection.
- Notifies the server that a user has joined.
- Listens for updates about connected users.
2. File Selection & Compression
Users can select a file, which is then compressed before sending.
Compressing a File Using Pako.js
const sendFile = (file: File) => { const reader = new FileReader(); reader.onloadend = () => { const arrayBuffer = reader.result as ArrayBuffer; const uint8Array = new Uint8Array(arrayBuffer); const compressedData = pako.deflate(uint8Array); ws?.send(JSON.stringify({ type: "file", to: selectedConnection, fileName: file.name, fileData: Array.from(compressedData), from: myName, })); }; reader.readAsArrayBuffer(file); };
- Reads the file as an ArrayBuffer.
- Converts it into a Uint8Array.
- Compresses it using Pako’s
deflate
function. - Sends it over WebSocket.
3. Receiving & Decompressing Files
When a file is received, it is first decompressed before saving.
const handleIncomingFile = (data) => { const compressedData = new Uint8Array(data.fileData); try { const decompressedData = pako.inflate(compressedData); setIncomingFiles([...incomingFiles, { fileName: data.fileName, fileData: decompressedData }]); } catch (error) { console.error("Decompression failed:", error); } };
- Extracts the compressed file data.
- Decompresses it using Pako’s
inflate
function. - Stores it for the user to download.
Backend Implementation
1. WebSocket Server Setup
import WebSocket, { WebSocketServer } from "ws"; const wss = new WebSocketServer({ port: 8080 }); const rooms: Record<string, { ws: WebSocket; name: string }[]> = {};
- Creates a WebSocket server.
- Stores active rooms and connected users.
2. Handling User Connections
wss.on("connection", (ws) => { ws.on("message", (message) => { const data = JSON.parse(message.toString()); if (data.type === "join_room") { if (!rooms[data.roomCode]) rooms[data.roomCode] = []; rooms[data.roomCode].push({ ws, name: data.name }); broadcastRoom(data.roomCode); } }); });
- Adds users to a room.
- Broadcasts updates when users join.
3. Handling File Transfers
function handleFileTransfer(data) { rooms[data.roomCode]?.forEach((client) => { if (client.name === data.to) { client.ws.send(JSON.stringify(data)); } }); }
- Routes compressed file data to the intended recipient.
Conclusion & Future Enhancements
This WebSocket-based file-sharing system provides real-time, efficient file transfers with Pako compression to optimize bandwidth usage. Future improvements may include:
- WebRTC for Peer-to-Peer transfers (eliminating the server bottleneck).
- Multi-file transfer support.
- End-to-end encryption for security.
This approach demonstrates how WebSockets, Pako.js, and file compression can be leveraged to build a high-performance file-sharing system.
Top comments (1)
I just tried IntraShare and I loved it! The real-time file transfer is incredibly smooth.
Can you provide open source if possible?