Elysia Tools
Navigation mobile
Real-time Communication
Exemples Socket.IO
Exemples de communication bidirectionnelle en temps réel utilisant Socket.IO avec salles, authentification et fonctionnalités avancées
Exemples
Entrées de cette collection
Application de Chat de Base Socket.IO
Application de chat complète en temps réel utilisant Socket.IO avec salles, gestion des utilisateurs et historique des messages
Difficulté
3/10
Temps estimé
15 min
Étiquettes
socket.io, chat, server, real-time
Prérequis
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}`);
});Composant Client Socket.IO React
Composant React moderne utilisant le client Socket.IO avec hooks pour la communication en temps réel
Difficulté
6/10
Temps estimé
25 min
Étiquettes
socket.io, react, client, typescript
Prérequis
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<ReturnType<typeof setTimeout> | 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;Fonctionnalités Avancées Socket.IO
Patterns avancés Socket.IO incluant authentification, namespaces, adaptateurs et scalabilité
Difficulté
9/10
Temps estimé
45 min
Étiquettes
socket.io, advanced, scaling, authentication
Prérequis
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 };Outils
Outils souvent utilisés avec cet exemple
Associé