Socket.IO Samples

Real-time bidirectional communication examples using Socket.IO with rooms, authentication, and advanced features

💻 Socket.IO Basic Chat Application javascript

🟢 simple ⭐⭐

Complete real-time chat application using Socket.IO with rooms, user management, and message history

⏱️ 15 min 🏷️ socket.io, chat, server, real-time
Prerequisites: Node.js, Socket.IO basics
// Socket.IO Basic Chat Application
// Server-side implementation with Express

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const path = require('path');

const app = express();
const server = http.createServer(app);
const io = socketIo(server, {
    cors: {
        origin: "*",
        methods: ["GET", "POST"]
    }
});

// Serve static files
app.use(express.static(path.join(__dirname, 'public')));

// Store active users and rooms
const users = new Map();
const rooms = new Map();
const messageHistory = new Map();

// Socket.IO connection handler
io.on('connection', (socket) => {
    console.log(`User connected: ${socket.id}`);

    // Handle user joining
    socket.on('join', (data) => {
        const { username, room } = data;

        // Join specified room
        socket.join(room);

        // Store user information
        users.set(socket.id, {
            id: socket.id,
            username,
            room,
            joinedAt: new Date()
        });

        // Initialize room if not exists
        if (!rooms.has(room)) {
            rooms.set(room, new Set());
            messageHistory.set(room, []);
        }

        rooms.get(room).add(socket.id);

        // Notify others in the room
        socket.to(room).emit('user_joined', {
            username,
            userId: socket.id,
            timestamp: new Date()
        });

        // Send room info to the user
        const roomUsers = Array.from(rooms.get(room))
            .map(id => users.get(id))
            .filter(Boolean)
            .map(user => ({
                id: user.id,
                username: user.username
            }));

        socket.emit('room_info', {
            room,
            users: roomUsers,
            messages: messageHistory.get(room) || []
        });

        console.log(`${username} joined room: ${room}`);
    });

    // Handle chat messages
    socket.on('send_message', (data) => {
        const user = users.get(socket.id);
        if (!user) return;

        const message = {
            id: generateMessageId(),
            userId: socket.id,
            username: user.username,
            room: user.room,
            message: data.message,
            timestamp: new Date()
        };

        // Store message in history
        if (!messageHistory.has(user.room)) {
            messageHistory.set(user.room, []);
        }
        messageHistory.get(user.room).push(message);

        // Limit message history
        const history = messageHistory.get(user.room);
        if (history.length > 100) {
            history.splice(0, history.length - 100);
        }

        // Broadcast message to room
        io.to(user.room).emit('receive_message', message);

        console.log(`Message in ${user.room}: ${user.username}: ${data.message}`);
    });

    // Handle typing indicators
    socket.on('typing_start', (data) => {
        const user = users.get(socket.id);
        if (!user) return;

        socket.to(user.room).emit('user_typing', {
            username: user.username,
            typing: true
        });
    });

    socket.on('typing_stop', (data) => {
        const user = users.get(socket.id);
        if (!user) return;

        socket.to(user.room).emit('user_typing', {
            username: user.username,
            typing: false
        });
    });

    // Handle private messages
    socket.on('private_message', (data) => {
        const sender = users.get(socket.id);
        if (!sender) return;

        const message = {
            id: generateMessageId(),
            from: socket.id,
            fromUsername: sender.username,
            to: data.toUserId,
            message: data.message,
            timestamp: new Date(),
            private: true
        };

        // Send to recipient
        io.to(data.toUserId).emit('private_message', message);

        // Send confirmation to sender
        socket.emit('message_sent', message);

        console.log(`Private message from ${sender.username} to ${data.toUserId}`);
    });

    // Handle room creation
    socket.on('create_room', (data) => {
        const { roomName, password } = data;
        const user = users.get(socket.id);

        if (!user) return;

        // Create new room
        if (!rooms.has(roomName)) {
            rooms.set(roomName, new Set());
            messageHistory.set(roomName, []);
        }

        // Join creator to the room
        socket.join(roomName);
        rooms.get(roomName).add(socket.id);

        socket.emit('room_created', {
            roomName,
            hasPassword: !!password
        });

        console.log(`Room created: ${roomName} by ${user.username}`);
    });

    // Handle leaving room
    socket.on('leave_room', () => {
        const user = users.get(socket.id);
        if (!user) return;

        socket.leave(user.room);

        // Remove user from room
        if (rooms.has(user.room)) {
            rooms.get(user.room).delete(socket.id);

            // Notify others
            socket.to(user.room).emit('user_left', {
                username: user.username,
                userId: socket.id,
                timestamp: new Date()
            });

            // Clean up empty rooms
            if (rooms.get(user.room).size === 0) {
                rooms.delete(user.room);
                messageHistory.delete(user.room);
            }
        }

        // Clear user data
        users.delete(socket.id);

        socket.emit('left_room');
        console.log(`${user.username} left room`);
    });

    // Handle getting room list
    socket.on('get_rooms', () => {
        const roomList = Array.from(rooms.keys()).map(roomName => ({
            name: roomName,
            userCount: rooms.get(roomName).size
        }));

        socket.emit('rooms_list', roomList);
    });

    // Handle disconnection
    socket.on('disconnect', () => {
        const user = users.get(socket.id);

        if (user) {
            // Notify others in the room
            if (rooms.has(user.room)) {
                rooms.get(user.room).delete(socket.id);

                socket.to(user.room).emit('user_left', {
                    username: user.username,
                    userId: socket.id,
                    timestamp: new Date()
                });

                // Clean up empty rooms
                if (rooms.get(user.room).size === 0) {
                    rooms.delete(user.room);
                    messageHistory.delete(user.room);
                }
            }

            users.delete(socket.id);
            console.log(`${user.username} disconnected`);
        } else {
            console.log(`Anonymous user disconnected: ${socket.id}`);
        }
    });
});

// Utility function to generate message ID
function generateMessageId() {
    return Math.random().toString(36).substr(2, 9);
}

// HTTP route for root
app.get('/', (req, res) => {
    res.sendFile(path.join(__dirname, 'public', 'index.html'));
});

// Start server
const PORT = process.env.PORT || 3000;
server.listen(PORT, () => {
    console.log(`Socket.IO chat server running on port ${PORT}`);
});

💻 Socket.IO React Client Component typescript

🟡 intermediate ⭐⭐⭐

Modern React component using Socket.IO client with hooks for real-time communication

⏱️ 25 min 🏷️ socket.io, react, client, typescript
Prerequisites: React, TypeScript, Socket.IO client
// Socket.IO React Client Component
import React, { useState, useEffect, useRef, useCallback } from 'react';
import { io, Socket } from 'socket.io-client';
import './ChatApp.css';

interface Message {
    id: string;
    username: string;
    message: string;
    timestamp: Date;
    userId: string;
    private?: boolean;
    from?: string;
    fromUsername?: string;
    to?: string;
}

interface User {
    id: string;
    username: string;
}

interface Room {
    name: string;
    userCount: number;
}

const ChatApp: React.FC = () => {
    const [socket, setSocket] = useState<Socket | null>(null);
    const [username, setUsername] = useState('');
    const [currentRoom, setCurrentRoom] = useState('');
    const [messages, setMessages] = useState<Message[]>([]);
    const [users, setUsers] = useState<User[]>([]);
    const [rooms, setRooms] = useState<Room[]>([]);
    const [inputMessage, setInputMessage] = useState('');
    const [isConnected, setIsConnected] = useState(false);
    const [isTyping, setIsTyping] = useState(false);
    const [typingUsers, setTypingUsers] = useState<string[]>([]);
    const [showRoomList, setShowRoomList] = useState(false);
    const [newRoomName, setNewRoomName] = useState('');
    const [targetUser, setTargetUser] = useState('');
    const [privateMessage, setPrivateMessage] = useState('');

    const messagesEndRef = useRef<HTMLDivElement>(null);
    const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);

    // Initialize Socket.IO connection
    useEffect(() => {
        const newSocket = io(process.env.REACT_APP_SOCKET_URL || 'http://localhost:3000', {
            transports: ['websocket', 'polling'],
            upgrade: true
        });

        setSocket(newSocket);

        newSocket.on('connect', () => {
            setIsConnected(true);
            console.log('Connected to Socket.IO server');
        });

        newSocket.on('disconnect', () => {
            setIsConnected(false);
            console.log('Disconnected from Socket.IO server');
        });

        return () => {
            newSocket.disconnect();
        };
    }, []);

    // Handle receiving messages
    useEffect(() => {
        if (!socket) return;

        socket.on('receive_message', (message: Message) => {
            setMessages(prev => [...prev, message]);
        });

        socket.on('private_message', (message: Message) => {
            setMessages(prev => [...prev, message]);
        });

        socket.on('room_info', (data: { room: string; users: User[]; messages: Message[] }) => {
            setUsers(data.users);
            setMessages(data.messages);
        });

        socket.on('rooms_list', (roomList: Room[]) => {
            setRooms(roomList);
        });

        socket.on('user_joined', (data: { username: string; userId: string }) => {
            setUsers(prev => [...prev, { id: data.userId, username: data.username }]);
        });

        socket.on('user_left', (data: { username: string; userId: string }) => {
            setUsers(prev => prev.filter(user => user.id !== data.userId));
        });

        socket.on('user_typing', (data: { username: string; typing: boolean }) => {
            setTypingUsers(prev => {
                if (data.typing) {
                    return [...prev.filter(u => u !== data.username), data.username];
                } else {
                    return prev.filter(u => u !== data.username);
                }
            });
        });

        socket.on('room_created', (data: { roomName: string; hasPassword: boolean }) => {
            setRooms(prev => [...prev, { name: data.roomName, userCount: 1 }]);
        });

        return () => {
            socket.off('receive_message');
            socket.off('private_message');
            socket.off('room_info');
            socket.off('rooms_list');
            socket.off('user_joined');
            socket.off('user_left');
            socket.off('user_typing');
            socket.off('room_created');
        };
    }, [socket]);

    // Auto-scroll to bottom
    useEffect(() => {
        messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
    }, [messages]);

    // Join room
    const joinRoom = useCallback(() => {
        if (socket && username && currentRoom) {
            socket.emit('join', { username, room: currentRoom });
            socket.emit('get_rooms');
        }
    }, [socket, username, currentRoom]);

    // Send message
    const sendMessage = useCallback(() => {
        if (socket && inputMessage.trim()) {
            socket.emit('send_message', { message: inputMessage.trim() });
            setInputMessage('');
            stopTyping();
        }
    }, [socket, inputMessage]);

    // Send private message
    const sendPrivateMessage = useCallback(() => {
        if (socket && targetUser && privateMessage.trim()) {
            const targetUserObj = users.find(u => u.username === targetUser);
            if (targetUserObj) {
                socket.emit('private_message', {
                    toUserId: targetUserObj.id,
                    message: privateMessage.trim()
                });
                setPrivateMessage('');
            }
        }
    }, [socket, targetUser, privateMessage, users]);

    // Create new room
    const createRoom = useCallback(() => {
        if (socket && newRoomName.trim()) {
            socket.emit('create_room', { roomName: newRoomName.trim() });
            setNewRoomName('');
        }
    }, [socket, newRoomName]);

    // Typing handlers
    const startTyping = useCallback(() => {
        if (!isTyping && socket) {
            setIsTyping(true);
            socket.emit('typing_start');

            if (typingTimeoutRef.current) {
                clearTimeout(typingTimeoutRef.current);
            }

            typingTimeoutRef.current = setTimeout(() => {
                stopTyping();
            }, 3000);
        }
    }, [isTyping, socket]);

    const stopTyping = useCallback(() => {
        if (isTyping && socket) {
            setIsTyping(false);
            socket.emit('typing_stop');

            if (typingTimeoutRef.current) {
                clearTimeout(typingTimeoutRef.current);
                typingTimeoutRef.current = null;
            }
        }
    }, [isTyping, socket]);

    // Handle input changes
    const handleMessageChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setInputMessage(e.target.value);
        if (e.target.value.trim()) {
            startTyping();
        } else {
            stopTyping();
        }
    };

    const handleKeyPress = (e: React.KeyboardEvent) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            sendMessage();
        }
    };

    return (
        <div className="chat-app">
            {!username ? (
                <div className="login-form">
                    <h2>Join Chat</h2>
                    <input
                        type="text"
                        placeholder="Enter your username"
                        value={username}
                        onChange={(e) => setUsername(e.target.value)}
                        onKeyPress={(e) => e.key === 'Enter' && setUsername(e.target.value)}
                    />
                </div>
            ) : !currentRoom ? (
                <div className="room-selection">
                    <h2>Welcome, {username}!</h2>
                    <div className="join-room">
                        <h3>Join Existing Room</h3>
                        <input
                            type="text"
                            placeholder="Room name"
                            value={currentRoom}
                            onChange={(e) => setCurrentRoom(e.target.value)}
                        />
                        <button onClick={joinRoom} disabled={!currentRoom}>
                            Join Room
                        </button>
                    </div>
                    <div className="create-room">
                        <h3>Create New Room</h3>
                        <input
                            type="text"
                            placeholder="New room name"
                            value={newRoomName}
                            onChange={(e) => setNewRoomName(e.target.value)}
                        />
                        <button onClick={createRoom} disabled={!newRoomName}>
                            Create Room
                        </button>
                    </div>
                    <div className="room-list">
                        <h3>Available Rooms</h3>
                        {rooms.map(room => (
                            <div key={room.name} className="room-item">
                                <span>{room.name}</span>
                                <span className="user-count">{room.userCount} users</span>
                                <button onClick={() => {
                                    setCurrentRoom(room.name);
                                    setTimeout(joinRoom, 100);
                                }}>
                                    Join
                                </button>
                            </div>
                        ))}
                    </div>
                </div>
            ) : (
                <div className="chat-container">
                    <div className="chat-header">
                        <div className="connection-status">
                            <span className={isConnected ? 'connected' : 'disconnected'} />
                            {isConnected ? 'Connected' : 'Disconnected'}
                        </div>
                        <div className="room-info">
                            Room: {currentRoom}
                        </div>
                        <div className="user-info">
                            {username}
                        </div>
                    </div>

                    <div className="chat-body">
                        <div className="sidebar">
                            <div className="users-section">
                                <h3>Users in Room</h3>
                                {users.map(user => (
                                    <div key={user.id} className="user-item">
                                        {user.username}
                                        {user.username !== username && (
                                            <button
                                                onClick={() => setTargetUser(user.username)}
                                                className="pm-btn"
                                            >
                                                PM
                                            </button>
                                        )}
                                    </div>
                                ))}
                            </div>
                            {targetUser && (
                                <div className="private-message">
                                    <h4>Private Message to {targetUser}</h4>
                                    <input
                                        type="text"
                                        placeholder="Type private message..."
                                        value={privateMessage}
                                        onChange={(e) => setPrivateMessage(e.target.value)}
                                        onKeyPress={(e) => e.key === 'Enter' && sendPrivateMessage()}
                                    />
                                    <button onClick={sendPrivateMessage} disabled={!privateMessage}>
                                        Send
                                    </button>
                                </div>
                            )}
                        </div>

                        <div className="main-chat">
                            <div className="messages-container">
                                {messages.map((message, index) => (
                                    <div
                                        key={message.id || index}
                                        className={`message ${message.userId === socket?.id ? 'own' : ''} ${message.private ? 'private' : ''}`}
                                    >
                                        <div className="message-header">
                                            <span className="message-username">
                                                {message.fromUsername || message.username}
                                            </span>
                                            <span className="message-timestamp">
                                                {new Date(message.timestamp).toLocaleTimeString()}
                                            </span>
                                            {message.private && <span className="private-indicator">🔒</span>}
                                        </div>
                                        <div className="message-content">
                                            {message.message}
                                        </div>
                                    </div>
                                ))}
                                {typingUsers.length > 0 && (
                                    <div className="typing-indicator">
                                        {typingUsers.join(', ')} {typingUsers.length === 1 ? 'is' : 'are'} typing...
                                    </div>
                                )}
                                <div ref={messagesEndRef} />
                            </div>

                            <div className="message-input">
                                <input
                                    type="text"
                                    placeholder="Type a message..."
                                    value={inputMessage}
                                    onChange={handleMessageChange}
                                    onKeyPress={handleKeyPress}
                                    disabled={!isConnected}
                                />
                                <button
                                    onClick={sendMessage}
                                    disabled={!inputMessage.trim() || !isConnected}
                                >
                                    Send
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            )}
        </div>
    );
};

export default ChatApp;

💻 Advanced Socket.IO Features javascript

🔴 complex ⭐⭐⭐⭐⭐

Advanced Socket.IO patterns including authentication, namespaces, adapters, and scalability

⏱️ 45 min 🏷️ socket.io, advanced, scaling, authentication
Prerequisites: Socket.IO, Redis, JWT, Node.js advanced
// Advanced Socket.IO Features Implementation
// Including authentication, namespaces, rooms, and Redis adapter

const express = require('express');
const http = require('http');
const socketIo = require('socket.io');
const redis = require('socket.io-redis');
const jwt = require('jsonwebtoken');
const rateLimit = require('express-rate-limit');
const helmet = require('helmet');

const app = express();
const server = http.createServer(app);

// Security middleware
app.use(helmet());

// Rate limiting
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 100 // limit each IP to 100 requests per windowMs
});

app.use(limiter);
app.use(express.json());

// Configure Socket.IO with advanced options
const io = socketIo(server, {
    cors: {
        origin: process.env.ALLOWED_ORIGINS?.split(',') || ['http://localhost:3000'],
        methods: ['GET', 'POST'],
        credentials: true
    },
    transports: ['websocket', 'polling'],
    pingTimeout: 60000,
    pingInterval: 25000,
    maxHttpBufferSize: 1e8, // 100 MB
    perMessageDeflate: {
        threshold: 1024
    }
});

// Redis adapter for multi-server scaling
if (process.env.REDIS_URL) {
    io.adapter(redis(process.env.REDIS_URL));
    console.log('Redis adapter enabled for scaling');
}

// JWT Secret
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';

// Authentication middleware for Socket.IO
const authenticateSocket = async (socket, next) => {
    try {
        const token = socket.handshake.auth.token ||
                     socket.handshake.headers.authorization?.replace('Bearer ', '');

        if (!token) {
            return next(new Error('Authentication token required'));
        }

        const decoded = jwt.verify(token, JWT_SECRET);
        socket.userId = decoded.userId;
        socket.username = decoded.username;
        socket.role = decoded.role || 'user';

        // Add custom properties
        socket.join(`user_${socket.userId}`); // Personal room for targeted messages

        next();
    } catch (error) {
        console.error('Socket authentication error:', error);
        next(new Error('Invalid authentication token'));
    }
};

// Apply authentication middleware
io.use(authenticateSocket);

// Main namespace - general chat and notifications
io.on('connection', (socket) => {
    console.log(`User connected: ${socket.username} (${socket.userId}) with role: ${socket.role}`);

    // Track user connection
    trackUserConnection(socket);

    // Handle joining rooms with permission checking
    socket.on('join_room', async (data) => {
        try {
            const { roomId, password } = data;

            // Verify room permissions
            const hasPermission = await checkRoomPermission(socket, roomId);
            if (!hasPermission) {
                return socket.emit('error', { message: 'Permission denied' });
            }

            // Join room
            await socket.join(roomId);
            socket.currentRoom = roomId;

            // Notify others
            socket.to(roomId).emit('user_joined', {
                userId: socket.userId,
                username: socket.username,
                role: socket.role,
                timestamp: new Date()
            });

            // Send room data
            const roomData = await getRoomData(roomId);
            socket.emit('room_joined', roomData);

            console.log(`${socket.username} joined room: ${roomId}`);
        } catch (error) {
            socket.emit('error', { message: 'Failed to join room' });
        }
    });

    // Handle file sharing with progress tracking
    socket.on('upload_file', async (data) => {
        try {
            const { roomId, fileName, fileSize, fileData } = data;

            // Check file size limits
            const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10MB
            if (fileSize > MAX_FILE_SIZE) {
                return socket.emit('upload_error', { message: 'File too large' });
            }

            // Process file upload in chunks
            const fileId = generateId();
            let uploadedBytes = 0;
            const chunkSize = 1024 * 1024; // 1MB chunks

            socket.emit('upload_started', { fileId, fileName, totalSize: fileSize });

            for (let i = 0; i < fileData.length; i += chunkSize) {
                const chunk = fileData.slice(i, i + chunkSize);
                uploadedBytes += chunk.length;

                // Process chunk (save to storage, etc.)
                await processFileChunk(fileId, chunk, i);

                // Send progress update
                socket.emit('upload_progress', {
                    fileId,
                    progress: Math.round((uploadedBytes / fileSize) * 100)
                });

                // Simulate processing delay
                await new Promise(resolve => setTimeout(resolve, 100));
            }

            // Notify room about new file
            const fileUrl = `/uploads/${fileId}/${fileName}`;
            socket.to(roomId).emit('file_shared', {
                fileId,
                fileName,
                fileSize,
                fileUrl,
                sharedBy: socket.username,
                timestamp: new Date()
            });

            socket.emit('upload_completed', { fileId, fileUrl });

        } catch (error) {
            socket.emit('upload_error', { message: 'Upload failed' });
        }
    });

    // Handle voice call signaling
    socket.on('voice_call', async (data) => {
        const { targetUserId, callType } = data; // callType: 'audio' or 'video'

        const callId = generateId();
        const callData = {
            callId,
            callerId: socket.userId,
            callerUsername: socket.username,
            callType,
            roomId: `call_${callId}`,
            timestamp: new Date()
        };

        // Create private room for the call
        await socket.join(callData.roomId);
        await io.to(targetUserId).socketsJoin(callData.roomId);

        // Send call invitation to target user
        io.to(targetUserId).emit('call_invitation', callData);

        // Handle call responses
        socket.on('call_response', (response) => {
            const { accepted, callId: responseCallId } = response;

            io.to(`call_${responseCallId}`).emit('call_response', {
                accepted,
                respondedBy: socket.userId,
                respondedByUsername: socket.username
            });

            if (!accepted) {
                // Clean up call room
                io.in(`call_${responseCallId}`).socketsLeave(`call_${responseCallId}`);
            }
        });

        // Handle WebRTC signaling
        socket.on('ice_candidate', (data) => {
            socket.to(`call_${data.callId}`).emit('ice_candidate', {
                candidate: data.candidate,
                fromUserId: socket.userId
            });
        });

        socket.on('offer', (data) => {
            socket.to(`call_${data.callId}`).emit('offer', {
                offer: data.offer,
                fromUserId: socket.userId
            });
        });

        socket.on('answer', (data) => {
            socket.to(`call_${data.callId}`).emit('answer', {
                answer: data.answer,
                fromUserId: socket.userId
            });
        });

        console.log(`Voice call initiated: ${socket.username} -> ${targetUserId}`);
    });

    // Handle admin commands
    if (socket.role === 'admin') {
        socket.on('admin_command', async (data) => {
            const { command, targetUserId, roomId, params } = data;

            switch (command) {
                case 'kick_user':
                    await kickUser(targetUserId, roomId);
                    break;
                case 'ban_user':
                    await banUser(targetUserId);
                    break;
                case 'mute_user':
                    await muteUser(targetUserId, roomId, params.duration);
                    break;
                case 'clear_room':
                    await clearRoomMessages(roomId);
                    break;
                case 'server_stats':
                    const stats = await getServerStats();
                    socket.emit('server_stats', stats);
                    break;
            }
        });
    }

    // Handle disconnection
    socket.on('disconnect', (reason) => {
        console.log(`User disconnected: ${socket.username} (${reason})`);

        // Clean up user data
        if (socket.currentRoom) {
            socket.to(socket.currentRoom).emit('user_left', {
                userId: socket.userId,
                username: socket.username,
                timestamp: new Date()
            });
        }

        removeUserConnection(socket);
    });
});

// Admin namespace - administrative operations
const adminNamespace = io.of('/admin');

adminNamespace.use((socket, next) => {
    // Enhanced authentication for admin namespace
    const token = socket.handshake.auth.token;

    try {
        const decoded = jwt.verify(token, JWT_SECRET);

        if (decoded.role !== 'admin') {
            return next(new Error('Admin access required'));
        }

        socket.userId = decoded.userId;
        socket.username = decoded.username;
        socket.role = 'admin';

        next();
    } catch (error) {
        next(new Error('Invalid admin credentials'));
    }
});

adminNamespace.on('connection', (socket) => {
    console.log(`Admin connected: ${socket.username}`);

    // Real-time server monitoring
    socket.on('get_stats', async () => {
        const stats = await getServerStats();
        socket.emit('stats', stats);
    });

    // System announcements
    socket.on('broadcast_announcement', (data) => {
        const { message, type = 'info', targetRole } = data;

        // Broadcast to all users or specific role
        if (targetRole) {
            io.to(`role_${targetRole}`).emit('announcement', {
                message,
                type,
                timestamp: new Date(),
                fromAdmin: socket.username
            });
        } else {
            io.emit('announcement', {
                message,
                type,
                timestamp: new Date(),
                fromAdmin: socket.username
            });
        }
    });
});

// Notification namespace - system notifications
const notificationNamespace = io.of('/notifications');

notificationNamespace.use(authenticateSocket);

notificationNamespace.on('connection', (socket) => {
    console.log(`Notification client connected: ${socket.username}`);

    // User preferences
    socket.on('update_preferences', (preferences) => {
        updateUserNotificationPreferences(socket.userId, preferences);
    });

    // Mark notifications as read
    socket.on('mark_read', (notificationIds) => {
        markNotificationsAsRead(socket.userId, notificationIds);
    });
});

// Utility functions
function generateId() {
    return Math.random().toString(36).substr(2, 9) + Date.now().toString(36);
}

async function checkRoomPermission(socket, roomId) {
    // Implement room permission logic
    // Check database, user roles, etc.
    return true; // Simplified for example
}

async function getRoomData(roomId) {
    // Fetch room data from database
    return {
        roomId,
        name: roomId,
        users: [], // Array of users in room
        messages: [], // Recent messages
        permissions: {
            canSendMessages: true,
            canSendFiles: true,
            canInviteUsers: true
        }
    };
}

async function processFileChunk(fileId, chunk, offset) {
    // Process and store file chunk
    // This would integrate with cloud storage, database, etc.
    await new Promise(resolve => setTimeout(resolve, 50));
}

async function kickUser(userId, roomId) {
    const socket = [...io.sockets.sockets.values()].find(s => s.userId === userId);
    if (socket) {
        socket.to(roomId).emit('user_kicked', { userId, username: socket.username });
        socket.leave(roomId);
        socket.emit('kicked', { roomId, reason: 'Kicked by admin' });
    }
}

async function banUser(userId) {
    // Implement user ban logic
    // Update database, disconnect user, prevent reconnection
}

async function muteUser(userId, roomId, duration) {
    // Implement user mute logic
    // Store mute information with expiration
}

async function clearRoomMessages(roomId) {
    // Clear all messages in a room
    // This would update the database
    io.to(roomId).emit('messages_cleared', { roomId });
}

async function getServerStats() {
    const sockets = await io.fetchSockets();

    return {
        connectedUsers: sockets.length,
        rooms: await getRoomCount(),
        messages: await getMessageCount(),
        uptime: process.uptime(),
        memory: process.memoryUsage(),
        timestamp: new Date()
    };
}

function trackUserConnection(socket) {
    // Track user connection in database
    // Store connection info, last seen, etc.
}

function removeUserConnection(socket) {
    // Remove user connection tracking
    // Update last seen, clean up resources
}

function updateUserNotificationPreferences(userId, preferences) {
    // Update user notification preferences in database
}

function markNotificationsAsRead(userId, notificationIds) {
    // Mark notifications as read in database
}

// Broadcast system notifications
function broadcastNotification(data) {
    notificationNamespace.emit('notification', {
        ...data,
        timestamp: new Date()
    });
}

// Send targeted notification to specific user
function sendUserNotification(userId, data) {
    notificationNamespace.to(`user_${userId}`).emit('notification', {
        ...data,
        timestamp: new Date()
    });
}

// Graceful shutdown
process.on('SIGTERM', () => {
    console.log('SIGTERM received, shutting down gracefully');
    server.close(() => {
        console.log('Server closed');
        process.exit(0);
    });
});

const PORT = process.env.PORT || 3001;
server.listen(PORT, () => {
    console.log(`Advanced Socket.IO server running on port ${PORT}`);
});

module.exports = { app, server, io, broadcastNotification, sendUserNotification };