2026-01-03 14:07:04 +00:00
|
|
|
import { io } from 'socket.io-client';
|
|
|
|
|
|
|
|
|
|
const WS_URL = import.meta.env.VITE_WS_URL || 'http://localhost:3000';
|
|
|
|
|
|
|
|
|
|
class SocketService {
|
|
|
|
|
constructor() {
|
|
|
|
|
this.socket = null;
|
|
|
|
|
this.listeners = new Map();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
connect() {
|
|
|
|
|
if (this.socket?.connected) {
|
|
|
|
|
return this.socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.socket = io(WS_URL, {
|
|
|
|
|
withCredentials: true,
|
|
|
|
|
transports: ['websocket', 'polling'],
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.socket.on('connect', () => {
|
|
|
|
|
console.log('WebSocket connected:', this.socket.id);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.socket.on('disconnect', () => {
|
|
|
|
|
console.log('WebSocket disconnected');
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
this.socket.on('error', (error) => {
|
|
|
|
|
console.error('WebSocket error:', error);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return this.socket;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
disconnect() {
|
|
|
|
|
if (this.socket) {
|
|
|
|
|
this.socket.disconnect();
|
|
|
|
|
this.socket = null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
on(event, callback) {
|
|
|
|
|
if (!this.socket) {
|
|
|
|
|
this.connect();
|
|
|
|
|
}
|
|
|
|
|
this.socket.on(event, callback);
|
|
|
|
|
|
|
|
|
|
if (!this.listeners.has(event)) {
|
|
|
|
|
this.listeners.set(event, []);
|
|
|
|
|
}
|
|
|
|
|
this.listeners.get(event).push(callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
off(event, callback) {
|
|
|
|
|
if (this.socket) {
|
|
|
|
|
this.socket.off(event, callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this.listeners.has(event)) {
|
|
|
|
|
const callbacks = this.listeners.get(event);
|
|
|
|
|
const index = callbacks.indexOf(callback);
|
|
|
|
|
if (index > -1) {
|
|
|
|
|
callbacks.splice(index, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit(event, data) {
|
|
|
|
|
if (!this.socket) {
|
|
|
|
|
this.connect();
|
|
|
|
|
}
|
|
|
|
|
this.socket.emit(event, data);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 22:03:42 +00:00
|
|
|
onReconnect(callback) {
|
|
|
|
|
if (!this.socket) {
|
|
|
|
|
this.connect();
|
|
|
|
|
}
|
|
|
|
|
// Слушаем событие 'connect' которое происходит при переподключении
|
|
|
|
|
this.socket.on('connect', callback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
offReconnect(callback) {
|
|
|
|
|
if (this.socket) {
|
|
|
|
|
this.socket.off('connect', callback);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-03 14:07:04 +00:00
|
|
|
// Game-specific methods
|
|
|
|
|
joinRoom(roomCode, userId) {
|
|
|
|
|
this.emit('joinRoom', { roomCode, userId });
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 17:56:00 +00:00
|
|
|
startGame(roomId, roomCode, userId) {
|
|
|
|
|
this.emit('startGame', { roomId, roomCode, userId });
|
2026-01-03 14:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-08 17:56:00 +00:00
|
|
|
endGame(roomId, roomCode, userId) {
|
|
|
|
|
this.emit('endGame', { roomId, roomCode, userId });
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-08 21:44:38 +00:00
|
|
|
// Note: Game actions now use 'playerAction' event with UUID
|
|
|
|
|
// Direct emit is preferred over these helper methods
|
|
|
|
|
// Example: socketService.emit('playerAction', { action: 'revealAnswer', ... })
|
|
|
|
|
|
2026-01-08 17:56:00 +00:00
|
|
|
updateRoomPack(roomId, roomCode, userId, questions) {
|
|
|
|
|
this.emit('updateRoomPack', { roomId, roomCode, userId, questions });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
importQuestions(roomId, roomCode, userId, sourcePackId, questionIndices) {
|
|
|
|
|
this.emit('importQuestions', {
|
|
|
|
|
roomId,
|
|
|
|
|
roomCode,
|
|
|
|
|
userId,
|
|
|
|
|
sourcePackId,
|
|
|
|
|
questionIndices,
|
|
|
|
|
});
|
2026-01-03 14:07:04 +00:00
|
|
|
}
|
2026-01-09 16:44:33 +00:00
|
|
|
|
|
|
|
|
updatePlayerName(roomId, roomCode, userId, participantId, newName) {
|
|
|
|
|
this.emit('updatePlayerName', {
|
|
|
|
|
roomId,
|
|
|
|
|
roomCode,
|
|
|
|
|
userId,
|
|
|
|
|
participantId,
|
|
|
|
|
newName,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
updatePlayerScore(roomId, roomCode, userId, participantId, newScore) {
|
|
|
|
|
this.emit('updatePlayerScore', {
|
|
|
|
|
roomId,
|
|
|
|
|
roomCode,
|
|
|
|
|
userId,
|
|
|
|
|
participantId,
|
|
|
|
|
newScore,
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-01-10 15:51:33 +00:00
|
|
|
|
|
|
|
|
changeRoomTheme(roomId, roomCode, userId, themeId) {
|
|
|
|
|
this.emit('changeRoomTheme', {
|
|
|
|
|
roomId,
|
|
|
|
|
roomCode,
|
|
|
|
|
userId,
|
|
|
|
|
themeId,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
changeParticipantRole(roomId, roomCode, userId, participantId, newRole) {
|
|
|
|
|
this.emit('changeParticipantRole', {
|
|
|
|
|
roomId,
|
|
|
|
|
roomCode,
|
|
|
|
|
userId,
|
|
|
|
|
participantId,
|
|
|
|
|
newRole,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toggleParticles(roomId, roomCode, userId, particlesEnabled) {
|
|
|
|
|
this.emit('toggleParticles', {
|
|
|
|
|
roomId,
|
|
|
|
|
roomCode,
|
|
|
|
|
userId,
|
|
|
|
|
particlesEnabled,
|
|
|
|
|
});
|
|
|
|
|
}
|
2026-01-03 14:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default new SocketService();
|