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?