(html) const express = require("express"); const http = require("http"); const { Server } = require("socket.io"); const app = express(); const server = http.createServer(app); const io = new Server(server); app.use(express.static("public")); io.on("connection", (socket) => { // announce join socket.on("join", (name) => { socket.data.name = name || "Anonymous"; socket.broadcast.emit("system", `${socket.data.name} joined the chat`); }); // receive chat message and broadcast socket.on("chat", (msg) => { const payload = { name: socket.data.name || "Anonymous", text: msg, time: new Date().toISOString() }; io.emit("chat", payload); }); socket.on("disconnect", () => { if (socket.data.name) { socket.broadcast.emit("system", `${socket.data.name} left the chat`); } }); }); const PORT = process.env.PORT || 3000; server.listen(PORT, () => console.log(`Server listening on http://localhost:${PORT}`)); *{box-sizing:border-box} body{font-family:Arial,Helvetica,sans-serif;margin:0;background:#f4f7fb;height:100vh} .container{display:flex;height:100%} .sidebar{width:220px;padding:16px;background:#2f3640;color:#fff} .sidebar h2{margin-top:0} .sidebar input{width:100%;padding:8px;margin-top:8px;border-radius:4px;border:0} .sidebar button{width:100%;padding:8px;margin-top:8px;border:none;border-radius:4px;background:#00a8ff;color:#fff;cursor:pointer} .chat{flex:1;display:flex;flex-direction:column} .messages{flex:1;padding:16px;overflow:auto} .msg{background:#fff;padding:8px 12px;border-radius:8px;margin-bottom:8px;max-width:75%} .msg.me{background:#c8e6c9;margin-left:auto} .sys{color:#666;font-style:italic;margin-bottom:8px} .composer{display:flex;padding:12px;background:#eee} .composer input{flex:1;padding:10px;border-radius:6px;border:1px solid #ccc} .composer button{margin-left:8px;padding:10px 16px;border-radius:6px;border:none;background:#2ecc71;color:#fff;cursor:pointer} const express = require("express"); const http = require("http"); const { Server } = require("socket.io"); const app = express(); const server = http.createServer(app); const io = new Server(server, { cors: { origin: "*" } }); app.use(express.static("public")); // In-memory store: { roomName: { users: {socketId: name}, history: [msg,...] } } const ROOMS = {}; const MAX_HISTORY = 100; function ensureRoom(room) { if (!ROOMS[room]) ROOMS[room] = { users: {}, history: [] }; } io.on("connection", (socket) => { socket.data.name = "Anonymous"; socket.on("join", ({ name, room }) => { name = (name || "Anonymous").slice(0, 24); room = (room || "lobby").slice(0, 32); socket.data.name = name; socket.data.room = room; socket.join(room); ensureRoom(room); ROOMS[room].users[socket.id] = name; // Send room info + history to joining client socket.emit("room_joined", { room, history: ROOMS[room].history, users: Object.values(ROOMS[room].users) }); // Notify others in room socket.to(room).emit("system", `${name} joined ${room}`); io.in(room).emit("users", Object.values(ROOMS[room].users)); }); socket.on("chat", (text) => { const room = socket.data.room || "lobby"; const payload = { id: Date.now().toString(36) + "-" + Math.random().toString(36).slice(2,8), name: socket.data.name || "Anonymous", const socket = io(); const form = document.getElementById("form"); const input = document.getElementById("input"); const messages = document.getElementById("messages"); const joinBtn = document.getElementById("joinBtn"); const nameInput = document.getElementById("nameInput"); const roomInput = document.getElementById("roomInput"); const usersEl = document.getElementById("users"); const pmSelect = document.getElementById("pmSelect"); const pmInput = document.getElementById("pmInput"); const pmSend = document.getElementById("pmSend"); const roomNameEl = document.getElementById("roomName"); const typingEl = document.getElementById("typing"); let myName = ""; let joined = false; let typingTimer = null; function appendMessage(html, cls) { const el = document.createElement("div"); el.className = cls || "msg"; el.innerHTML = html; messages.appendChild(el); messages.scrollTop = messages.scrollHeight; } function escapeHtml(s = "") { return s.replace(/[&<>"']/g, (c) => ({ "&":"&","<":"<",">":">",'"':""","'":"'" })[c]); } joinBtn.addEventListener("click", () => { const name = (nameInput.value || "Anonymous").trim(); const room = (roomInput.value || "lobby").trim(); myName = name; socket.emit("join", { name, room }); joined = true; nameInput.disabled = true; roomInput.disabled = true; joinBtn.disabled = true; roomNameEl.textContent = `Room: ${room}`; }); form.addEventListener("submit", (e) => { .users{max-height:180px;overflow:auto;padding:8px;background:#fff;border-radius:6px} .user{padding:6px;border-bottom:1px solid #eee} .room-name{padding:8px 12px;background:#fff;border-bottom:1px solid #ddd} .typing{padding:6px 12px;color:#666;font-style:italic} .msg.pm{background:#ffe0b2} .time{font-size:0.8em;color:#888;margin-left:8px}