Socket.IOAdvanced
Building a Real-Time Chat Application
Rooms, message, typing ও system event সহ সম্পূর্ণ realtime chat app — বাংলায় project গাইড।
20টি অংশবাংলা ভাষায়
এখন পর্যন্ত যা শিখেছি তা কাজে লাগিয়ে একটি সম্পূর্ণ real-time chat application বানাই। এতে থাকবে room join, message পাঠানো, typing indicator, আর online presence।
শেখার লক্ষ্য
- একটি পূর্ণ project-এ multiple concept একসাথে প্রয়োগ
- room ভিত্তিক chat server
- browser client যুক্ত করা
- একটি সম্পূর্ণ mini-project শুরু থেকে শেষ করা
Feature List
- User room-এ join/leave
- Room-এর বাকি সবাই message পায়
- System message (কেউ join/leave করলে)
- Typing indicator
- Online user count
- Message history (in-memory)
Project Structure
mini-chat/
├── server.js
├── package.json
└── public/
└── index.htmlnpm init -y
npm install socket.ioServer
server.jsjavascript
javascript
// server.js
const { createServer } = require("node:http");
const { readFileSync } = require("node:fs");
const { Server } = require("socket.io");
const httpServer = createServer((req, res) => {
if (req.url === "/") {
res.writeHead(200, { "Content-Type": "text/html" });
res.end(readFileSync("public/index.html"));
return;
}
res.writeHead(404);
res.end();
});
const io = new Server(httpServer, {
cors: { origin: "*" },
});
// room → সর্বশেষ 50 message
const history = new Map();
io.on("connection", (socket) => {
console.log("connected:", socket.id);
// online count ছড়িয়ে দিন
io.emit("presence", io.engine.clientsCount);
socket.on("room:join", ({ room, name }) => {
if (typeof room !== "string" || !room.trim()) return;
socket.join(room);
socket.data.room = room;
socket.data.name = String(name || "anonymous").slice(0, 30);
// মিসড history পাঠান
socket.emit("room:history", history.get(room) || []);
// অন্যান্য সদস্যকে system message
socket.to(room).emit("system", `${socket.data.name} room-এ এসেছে`);
console.log(socket.data.name, "joined", room);
});
socket.on("chat:message", (text) => {
const room = socket.data.room;
if (!room) return;
const clean = String(text || "").trim().slice(0, 500);
if (!clean) return;
const msg = {
id: socket.id + "-" + Date.now(),
name: socket.data.name,
text: clean,
at: Date.now(),
};
// history রাখুন
const list = history.get(room) || [];
list.push(msg);
if (list.length > 50) list.shift();
history.set(room, list);
// room-এর সবাই (sender সহ)
io.to(room).emit("chat:message", msg);
});
socket.on("typing", () => {
if (socket.data.room) {
socket.to(socket.data.room).emit("typing", socket.data.name);
}
});
socket.on("disconnect", () => {
const room = socket.data.room;
if (room) {
socket.to(room).emit("system", `${socket.data.name} চলে গেছে`);
}
io.emit("presence", io.engine.clientsCount);
});
});
httpServer.listen(3000, () => {
console.log("http://localhost:3000");
});Client
public/index.htmlhtml
html
<!DOCTYPE html>
<html lang="bn">
<head>
<meta charset="UTF-8" />
<title>Mini Chat</title>
</head>
<body>
<h1>Mini Chat</h1>
<div id="join" hidden>
<input id="name" placeholder="আপনার নাম" />
<input id="room" placeholder="room নাম" />
<button id="joinBtn">Join</button>
</div>
<div id="chat" hidden>
<p id="status"></p>
<p id="online"></p>
<ul id="messages"></ul>
<p id="typing"></p>
<input id="text" placeholder="একটি message লিখুন..." />
<button id="send">পাঠান</button>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
const socket = io();
const name = prompt("আপনার নাম:") || "guest";
const room = prompt("Room নাম:") || "general";
document.getElementById("join").hidden = false;
socket.on("connect", () => {
socket.emit("room:join", { room, name });
document.getElementById("chat").hidden = false;
document.getElementById("join").hidden = true;
document.getElementById("status").textContent =
`Room: ${room} | আপনি: ${name}`;
});
socket.on("room:history", (list) => {
list.forEach(addMessage);
});
socket.on("chat:message", addMessage);
socket.on("system", (text) => {
addMessage({ name: "", text: "🔔 " + text });
});
socket.on("typing", (who) => {
const el = document.getElementById("typing");
el.textContent = who + " typing...";
clearTimeout(el._t);
el._t = setTimeout(() => (el.textContent = ""), 1500);
});
socket.on("presence", (n) => {
document.getElementById("online").textContent = `Online: ${n}`;
});
function addMessage({ name, text }) {
const li = document.createElement("li");
li.textContent = name ? `${name}: ${text}` : text;
document.getElementById("messages").appendChild(li);
}
const input = document.getElementById("text");
input.addEventListener("input", () => socket.emit("typing"));
document.getElementById("send").onclick = () => {
socket.emit("chat:message", input.value);
input.value = "";
};
input.addEventListener("keydown", (e) => {
if (e.key === "Enter") document.getElementById("send").click();
});
</script>
</body>
</html>Run
node server.js
# দুই browser tab খুলে ভিন্ন নাম দিয়ে একই room-এ join করুন
# একটিতে message লিখলে অন্যটিতে সাথে সাথে দেখবেনExpected Behavior
- একই room-এর সব client message পায়
- নতুন সদস্য যোগ হলে system message
- typing লিখলে অন্যদের স্ক্রিনে indicator
- online user count সাথে সাথে update হয়
- reconnect করলে history থেকে message ফিরে আসে
আরও বাড়ান
যোগ করা যেতে পারে: private message (Private & Group Messaging), message persist database-এ, auth (Authentication), acknowledged delivery (Acknowledgements), অথবা XSS থেকে বাঁচতে text escape।
Practice Task
- history DB-তে রাখুন যাতে server restart-এর পরও টেকে
- room list তৈরি করে দেখান —
io.sockets.adapter.rooms chat:message-এ ack যোগ করে "delivered" দেখান- server-এ input থেকে HTML strip করে XSS ঠেকান
সম্পর্কিত অধ্যায়: Rooms · Private and Group Messaging · Best Practices
শেষ প্যারায় নিজে practice করুন — কোড কপি করে নিজের এডিটরে চালিয়ে দেখুন।