mirror of
https://github.com/arthur-pbty/visio.git
synced 2026-06-03 23:36:40 +02:00
739fa54719
feat: create SocketContext for managing socket connections feat: implement useLocalStorage hook for persistent state management feat: set up SQLite database with room management functions feat: add utility functions for generating room IDs and formatting dates
228 lines
6.3 KiB
JavaScript
228 lines
6.3 KiB
JavaScript
const { createServer } = require('http');
|
|
const { parse } = require('url');
|
|
const next = require('next');
|
|
const { Server } = require('socket.io');
|
|
const Database = require('better-sqlite3');
|
|
const path = require('path');
|
|
|
|
const dev = process.env.NODE_ENV !== 'production';
|
|
const hostname = 'localhost';
|
|
const port = parseInt(process.env.PORT || '3000', 10);
|
|
|
|
const app = next({ dev, hostname, port });
|
|
const handle = app.getRequestHandler();
|
|
|
|
// Connexion à la base de données SQLite
|
|
const dbPath = path.join(process.cwd(), 'visio.db');
|
|
const db = new Database(dbPath);
|
|
|
|
// Fonction pour nettoyer les salles inactives dans la DB
|
|
function cleanupInactiveRoomsInDB() {
|
|
const stmt = db.prepare(`
|
|
UPDATE rooms SET is_active = 0
|
|
WHERE is_active = 1
|
|
AND datetime(last_activity, '+5 minutes') < datetime('now')
|
|
`);
|
|
const result = stmt.run();
|
|
if (result.changes > 0) {
|
|
console.log(`Nettoyage: ${result.changes} salle(s) inactive(s) fermée(s)`);
|
|
}
|
|
return result.changes;
|
|
}
|
|
|
|
// Stockage des salles et participants en mémoire
|
|
const rooms = new Map();
|
|
const roomTimers = new Map();
|
|
|
|
// Durée d'inactivité avant fermeture (5 minutes)
|
|
const INACTIVITY_TIMEOUT = 5 * 60 * 1000;
|
|
|
|
app.prepare().then(() => {
|
|
// Nettoyer les salles inactives au démarrage
|
|
console.log('Nettoyage des salles inactives au démarrage...');
|
|
cleanupInactiveRoomsInDB();
|
|
|
|
// Lancer un nettoyage périodique toutes les minutes
|
|
setInterval(() => {
|
|
cleanupInactiveRoomsInDB();
|
|
}, 60 * 1000);
|
|
|
|
const httpServer = createServer((req, res) => {
|
|
const parsedUrl = parse(req.url, true);
|
|
handle(req, res, parsedUrl);
|
|
});
|
|
|
|
const io = new Server(httpServer, {
|
|
cors: {
|
|
origin: '*',
|
|
methods: ['GET', 'POST']
|
|
}
|
|
});
|
|
|
|
// Fonction pour réinitialiser le timer d'inactivité
|
|
function resetRoomTimer(roomId) {
|
|
if (roomTimers.has(roomId)) {
|
|
clearTimeout(roomTimers.get(roomId));
|
|
}
|
|
|
|
const timer = setTimeout(() => {
|
|
const room = rooms.get(roomId);
|
|
if (room && room.participants.size === 0) {
|
|
console.log(`Fermeture de la salle ${roomId} pour inactivité`);
|
|
io.to(roomId).emit('room-closed');
|
|
rooms.delete(roomId);
|
|
roomTimers.delete(roomId);
|
|
|
|
// Marquer la salle comme fermée dans la DB
|
|
fetch(`http://localhost:${port}/api/rooms/${roomId}`, {
|
|
method: 'DELETE'
|
|
}).catch(console.error);
|
|
}
|
|
}, INACTIVITY_TIMEOUT);
|
|
|
|
roomTimers.set(roomId, timer);
|
|
}
|
|
|
|
io.on('connection', (socket) => {
|
|
console.log('Nouvelle connexion:', socket.id);
|
|
|
|
let currentRoom = null;
|
|
let currentUser = null;
|
|
|
|
socket.on('join-room', ({ roomId, userName }) => {
|
|
currentRoom = roomId;
|
|
currentUser = { id: socket.id, name: userName, videoOff: false, muted: false };
|
|
|
|
// Rejoindre la room Socket.io
|
|
socket.join(roomId);
|
|
|
|
// Initialiser ou récupérer la salle
|
|
if (!rooms.has(roomId)) {
|
|
rooms.set(roomId, {
|
|
participants: new Map()
|
|
});
|
|
}
|
|
|
|
const room = rooms.get(roomId);
|
|
|
|
// Envoyer la liste des participants existants au nouveau (avec leur état audio/vidéo)
|
|
const existingUsers = Array.from(room.participants.values());
|
|
socket.emit('existing-users', { users: existingUsers });
|
|
|
|
// Ajouter le nouveau participant
|
|
room.participants.set(socket.id, currentUser);
|
|
|
|
// Notifier les autres de la nouvelle connexion
|
|
socket.to(roomId).emit('user-joined', {
|
|
userId: socket.id,
|
|
userName: userName
|
|
});
|
|
|
|
// Réinitialiser le timer d'inactivité
|
|
resetRoomTimer(roomId);
|
|
|
|
console.log(`${userName} a rejoint la salle ${roomId}`);
|
|
});
|
|
|
|
socket.on('offer', ({ offer, to }) => {
|
|
const room = rooms.get(currentRoom);
|
|
const fromUser = room?.participants.get(socket.id);
|
|
|
|
socket.to(to).emit('offer', {
|
|
offer,
|
|
from: socket.id,
|
|
fromName: fromUser?.name || 'Inconnu'
|
|
});
|
|
});
|
|
|
|
socket.on('answer', ({ answer, to }) => {
|
|
socket.to(to).emit('answer', {
|
|
answer,
|
|
from: socket.id
|
|
});
|
|
});
|
|
|
|
socket.on('ice-candidate', ({ candidate, to }) => {
|
|
socket.to(to).emit('ice-candidate', {
|
|
candidate,
|
|
from: socket.id
|
|
});
|
|
});
|
|
|
|
socket.on('name-change', ({ name }) => {
|
|
if (currentRoom && currentUser) {
|
|
currentUser.name = name;
|
|
const room = rooms.get(currentRoom);
|
|
if (room) {
|
|
room.participants.set(socket.id, currentUser);
|
|
}
|
|
|
|
socket.to(currentRoom).emit('user-name-changed', {
|
|
userId: socket.id,
|
|
newName: name
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on('video-toggle', ({ videoOff }) => {
|
|
if (currentRoom && currentUser) {
|
|
currentUser.videoOff = videoOff;
|
|
const room = rooms.get(currentRoom);
|
|
if (room) {
|
|
room.participants.set(socket.id, currentUser);
|
|
}
|
|
|
|
socket.to(currentRoom).emit('user-video-toggle', {
|
|
userId: socket.id,
|
|
videoOff
|
|
});
|
|
}
|
|
});
|
|
|
|
socket.on('audio-toggle', ({ muted }) => {
|
|
if (currentRoom && currentUser) {
|
|
currentUser.muted = muted;
|
|
const room = rooms.get(currentRoom);
|
|
if (room) {
|
|
room.participants.set(socket.id, currentUser);
|
|
}
|
|
|
|
socket.to(currentRoom).emit('user-audio-toggle', {
|
|
userId: socket.id,
|
|
muted
|
|
});
|
|
}
|
|
});
|
|
|
|
// Répondre aux pings des clients pour la détection de déconnexion
|
|
socket.on('ping-server', () => {
|
|
socket.emit('pong-server');
|
|
});
|
|
|
|
socket.on('disconnect', () => {
|
|
if (currentRoom) {
|
|
const room = rooms.get(currentRoom);
|
|
if (room) {
|
|
room.participants.delete(socket.id);
|
|
|
|
// Notifier les autres
|
|
socket.to(currentRoom).emit('user-left', {
|
|
userId: socket.id
|
|
});
|
|
|
|
console.log(`Utilisateur ${socket.id} a quitté la salle ${currentRoom}`);
|
|
|
|
// Si la salle est vide, démarrer le timer de fermeture
|
|
if (room.participants.size === 0) {
|
|
resetRoomTimer(currentRoom);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
httpServer.listen(port, () => {
|
|
console.log(`> Serveur prêt sur http://${hostname}:${port}`);
|
|
});
|
|
});
|