Skip to content

Архитектура WebSocket

Planner использует Socket.IO для двунаправленной связи в реальном времени. Существует три отдельных пространства имён (namespace), каждое из которых обслуживает свою область.

Обзор

NamespaceНазначениеАутентификацияНаправление
/notificationspush-уведомленияJWTСервер → Клиент
/chatобмен сообщениямиJWTДвунаправленный
/videoсигналинг видеокомнатJWTДвунаправленный

Аутентификация

Все WebSocket-соединения аутентифицируются через handshake.auth.token — JWT-токен доступа, передаваемый при рукопожатии Socket.IO. Сервер проверяет токен с помощью JwtService и извлекает ID пользователя.

typescript
// Подключение клиента
const socket = io('/notifications', {
  auth: { token: accessToken }
})

Пространства имён

/notifications

Только серверная отправка — клиенты слушают события, без сообщений от клиента.

НаправлениеСобытиеPayloadОписание
Сервер → Клиентnotification:newОбъект NotificationНовое уведомление для пользователя

Пользователи автоматически присоединяются к комнате user:<id> при подключении.

/chat

Двунаправленный обмен сообщениями для разговоров в реальном времени.

НаправлениеСобытиеPayloadОписание
Клиент → СерверjoinconversationIdПрисоединиться к комнате разговора
Клиент → СерверleaveconversationIdПокинуть комнату разговора
Клиент → СерверtypingconversationIdИндикатор набора текста
Сервер → Клиентchat:typing{ conversationId, userId }Другой пользователь печатает

Сообщения отправляются через REST (POST /api/chats/:id/messages), доставка в реальном времени обрабатывается sendToConversation() на сервере. Пользователи присоединяются к комнатам user:<id> и conv:<id>.

/video

Сигналинг и события комнат для видеоконференций.

НаправлениеСобытиеPayloadОписание
Клиент → СерверjoinroomIdПрисоединиться к комнате (room:<id>)
Клиент → СерверleaveroomIdПокинуть комнату
Клиент → СерверsignalWebRTC-сигналРетрансляция сигналинга
Сервер → Клиентvideo:participant_joinedДанные участникаПользователь присоединился
Сервер → Клиентvideo:participant_leftДанные участникаПользователь покинул
Сервер → Клиентvideo:room_updatedДанные комнатыСостояние комнаты изменилось
Сервер → Клиентvideo:call_startedДанные комнатыМгновенный вызов начат

Структура комнат

Notifications:  user:<userId>
Chat:           user:<userId>, conv:<conversationId>
Video:          room:<roomId>

Интеграция с фронтендом

Слушатель уведомлений (в App.vue)

typescript
const socket = io('/notifications', { auth: { token } })
socket.on('notification:new', (notification) => {
  notificationsStore.addNotification(notification)
})

Store чата

typescript
const socket = io('/chat', { auth: { token } })
socket.on('chat:typing', ({ conversationId, userId }) => { /* ... */ })
socket.emit('join', conversationId)
socket.emit('typing', conversationId)

Store видео

typescript
const socket = io('/video', { auth: { token } })
socket.on('video:participant_joined', (data) => { /* ... */ })
socket.on('video:participant_left', (data) => { /* ... */ })
socket.emit('join', roomId)

Ключевые детали

  • NotificationsGateway.sendToUser() проверяет this.server? (сервер не определён во время тестирования)
  • Уведомления доставляются без ожидания — NotificationsService.create() не ожидается (fire-and-forget)
  • Сообщения чата сохраняются через REST, доставка в реальном времени — через WebSocket
  • Видеосигналинг ретранслирует WebRTC-оферы/ответы/ICE-кандидаты через namespace /video