Corp/WEBSOCKET_UNIFIED_MIGRATION.md

365 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Миграция на единое WebSocket соединение
## Что изменилось
### До (старая архитектура - 2 WebSocket):
```
Пользователь → 2 WebSocket соединения:
├─ ws://host/ws/chats/ (глобальный - для списка чатов и бейджа)
└─ ws://host/ws/chat/123/ (конкретный чат - только если открыт)
```
**Проблемы:**
- Двойная подписка на группы `chat_{id}`
- Дублирование событий
- Больше нагрузка на сервер
- Сложность управления
### После (новая архитектура - 1 WebSocket):
```
Пользователь → 1 WebSocket соединение:
└─ ws://host/ws/ (универсальное для пользователя)
├─ Чаты: список + активный чат
├─ Уведомления (звонки, события, задачи)
├─ Бейджи в sidebar
├─ Онлайн-статус
└─ Другие real-time события
```
**Преимущества:**
- ✅ Одно соединение вместо двух
- ✅ Нет дублирования событий
- ✅ Меньше нагрузка на сервер (50% соединений)
- ✅ Проще отладка
- ✅ Быстрее переключение между чатами
- ✅ Универсальное для всех типов обновлений
- ✅ Масштабируемость (легко добавить новые типы событий)
## Изменения в файлах
### Backend
#### 1. `communications/user_consumer.py` (НОВЫЙ)
Универсальный Consumer для всех real-time операций пользователя.
**Назначение:**
- 🔵 **Чаты**: подписка на все чаты, отслеживание активного
- 🔔 **Уведомления**: (будущее) звонки, события, задачи
- 🔢 **Бейджи**: обновление счетчиков в sidebar
- 🟢 **Статусы**: (будущее) онлайн/офлайн пользователей
- 📅 **События**: (будущее) календарь, документы и др.
**Ключевые особенности:**
- Подписывается на все чаты пользователя при подключении
- Отслеживает активный чат (`active_chat_id`)
- Отправляет полные данные для активного чата
- Отправляет компактные данные для обновления списка
- Управляется через действия: `open_chat`, `close_chat`
#### 2. `communications/routing.py` (ОБНОВЛЕН)
```python
# Универсальный WebSocket endpoint
re_path(r"^ws/$", UserConsumer.as_asgi(), name="ws_user")
```
### Frontend
#### 3. `static/js/components/userWebSocket.js` (НОВЫЙ)
Универсальный клиентский модуль для WebSocket пользователя.
**API:**
```javascript
const api = {
// Управление чатом
openChat(chatId, loadHistory),
closeChat(chatId),
// Отправка сообщений
sendMessage(content),
// Реакции
addReaction(messageId, emoji),
removeReaction(messageId, emoji),
// Редактирование
editMessage(messageId, content),
deleteMessage(messageId),
// Отметка прочитанного
markRead(chatId),
// Голосование
votePoll(pollId, optionIds),
// Состояние
getActiveChatId(),
isConnected()
};
```
#### 4. `templates/base.html` (ОБНОВЛЕН)
- Заменен `initChatWebSocket` на `initUnifiedChatWebSocket`
- Удален отдельный глобальный WebSocket для списка чатов
- Обновлен `initSidebarBadge` для работы с событиями из единого WS
## Протокол WebSocket
### Клиент → Сервер (действия)
```javascript
// Открыть чат
{
action: "open_chat",
chat_id: 123,
load_history: true
}
// Закрыть чат
{
action: "close_chat",
chat_id: 123
}
// Отправить сообщение
{
action: "send_message",
content: "Привет!"
}
// Добавить реакцию
{
action: "add_reaction",
message_id: 456,
emoji: "👍"
}
// Индикатор печати
{
action: "typing"
}
// Отметить прочитанным
{
action: "mark_read",
chat_id: 123
}
```
### Сервер → Клиент (события)
```javascript
// Новое сообщение (полные данные для активного чата)
{
type: "new_message",
chat_id: 123,
message: { id, content, author_id, ... }
}
// Обновление списка (компактные данные для всех чатов)
{
type: "list_update",
chat_id: 123,
message: { id, content, author_id, created_ts }
}
// Реакция добавлена
{
type: "reaction_added",
chat_id: 123,
message_id: 456,
emoji: "👍",
user_id: 789
}
// Пользователь печатает
{
type: "typing_start",
chat_id: 123,
user_id: 789,
user_name: "Иван"
}
// Ping для keepalive
{
type: "ping",
timestamp: "2025-12-01T12:00:00Z"
}
```
## Логика работы
### При загрузке страницы:
1. **Любая страница (авторизованный пользователь):**
- Создается единое WebSocket соединение: `ws://host/ws/user/`
- Сервер подписывает на все чаты пользователя
- Начинается прослушивание событий
2. **Страница чата (/chats/123/):**
- WebSocket уже открыт
- Клиент отправляет `open_chat` с `chat_id: 123`
- Сервер устанавливает `active_chat_id = 123`
- Сервер отправляет начальную историю (если запрошена)
- Клиент начинает получать полные данные сообщений
3. **Переход к другому чату:**
- Клиент отправляет `close_chat` для текущего
- Клиент отправляет `open_chat` для нового
- WebSocket остается открытым!
### При получении нового сообщения:
**На сервере (`UnifiedChatConsumer.chat_message`):**
```python
chat_id = event['chat_id']
# Если это активный чат - полные данные
if chat_id == self.active_chat_id:
send_json({"type": "new_message", "message": full_data})
# Для списка - компактные данные
send_json({"type": "list_update", "message": compact_data})
```
**На клиенте:**
```javascript
// new_message - добавляем в DOM активного чата
handleNewMessage(data) {
const msgEl = createMessageElement(data.message);
scrollEl.appendChild(msgEl);
}
// list_update - обновляем карточку чата + бейдж
handleListUpdate(data) {
updateChatCard(data.chat_id, data.message);
badgeManager.incrementChat(data.chat_id);
}
```
## Обратная совместимость
Для плавной миграции:
1. **Старые endpoints закомментированы**, но не удалены
2. **API совместимо**: `window.chatWebSocketApi` и `window.chatWebSocket` работают
3. **События совместимы**: `chat:ws-ready`, `chat:list-update` и др.
## План полной миграции
### Этап 1: ✅ Создание (выполнено)
- [x] Создан `UnifiedChatConsumer`
- [x] Создан `unifiedChatWebSocket.js`
- [x] Обновлен routing
- [x] Обновлен base.html
### Этап 2: Тестирование
- [ ] Проверить работу в разных браузерах
- [ ] Проверить переключение между чатами
- [ ] Проверить обновление бейджа
- [ ] Проверить индикатор "печатает..."
- [ ] Проверить реакции и редактирование
### Этап 3: Очистка
- [ ] Удалить `ChatConsumer` и `ChatListConsumer`
- [ ] Удалить `chatWebSocket.js`
- [ ] Удалить старые endpoints из routing
- [ ] Обновить документацию
## Тестирование
### Проверка соединения:
```javascript
// В консоли браузера
console.log(window.chatWebSocketApi);
console.log(window.chatWebSocketApi.isConnected()); // true
// Открыть чат
window.chatWebSocketApi.openChat(123, true);
// Отправить сообщение
window.chatWebSocketApi.sendMessage("Тест");
```
### Проверка в Network DevTools:
1. Открыть DevTools → Network → WS
2. Найти соединение `ws/user/`
3. Проверить входящие/исходящие сообщения
4. Убедиться, что только одно WebSocket соединение активно
## Производительность
### До:
```
1 пользователь = 2 WebSocket (если открыт чат) или 1 (если только список)
100 пользователей с открытыми чатами = 200 WebSocket соединений
```
### После:
```
1 пользователь = 1 WebSocket (всегда)
100 пользователей = 100 WebSocket соединений
```
**Экономия: 50% соединений!**
## Известные ограничения
1. **История сообщений**: Загружается только при `load_history: true`
2. **Переподключение**: Автоматическое переподключение до 5 попыток
3. **Keepalive**: Ping каждые 20 секунд (можно настроить)
## Troubleshooting
### Проблема: WebSocket не подключается
**Решение:**
```javascript
// Проверить URL
console.log(location.host); // должен быть правильный хост
// Проверить авторизацию
console.log(window.currentUserId); // должен быть ID пользователя
```
### Проблема: Сообщения не появляются
**Решение:**
```javascript
// Проверить активный чат
console.log(window.chatWebSocketApi.getActiveChatId()); // должен быть chat_id
// Переоткрыть чат
const chatId = parseInt(document.getElementById('chatScroll').dataset.chatId);
window.chatWebSocketApi.closeChat(chatId);
window.chatWebSocketApi.openChat(chatId, true);
```
### Проблема: Бейдж не обновляется
**Решение:**
Проверить, что события диспатчатся:
```javascript
window.addEventListener('chat:list-update', (e) => {
console.log('List update:', e.detail);
});
```
## Дополнительные улучшения (будущее)
1. **Redis для typing status** - кэширование статуса печати
2. **Compression** - сжатие WebSocket сообщений
3. **Binary protocol** - для вложений
4. **Presence** - онлайн статус пользователей
5. **Read receipts** - уведомления о прочтении
6. **Message queue** - очередь для offline сообщений
---
**Статус: READY FOR TESTING**
**Дата: 1 декабря 2025 г.**
**Автор: IgorNadein**