62686ad834c5a53525ca42de5fbff3d094afc08c
Чат с общей комнатой
Веб-приложение чата с одной общей комнатой на WebSocket.
Текстовые сообщения, файлы, изображения, аудио, видео и голосовые сообщения.
Сервер: Node.js + ws
Клиент: React + Vite
Прокси: nginx (production-сборка)
Быстрый запуск (разработка)
Сервер
cd server
npm install
npm start
WebSocket сервер на ws://localhost:8080.
Клиент
cd client
npm install
npx vite
Dev-сервер на http://localhost:3000.
Клиент подключается напрямую к ws://localhost:8080.
Пользователи по умолчанию
| Логин | Пароль |
|---|---|
| alice | 123 |
| bob | 456 |
Production (Docker)
Сборка и запуск
docker build -t chat-app .
docker run -d -p 80:80 chat-app
Открой http://localhost.
Как это работает
- nginx на порту 80 раздаёт статику React и проксирует WebSocket
- Путь
/→ статические файлы клиента - Путь
/ws→ прокси на Node.js сервер (порт 8080 внутри контейнера) - nginx поддерживает Upgrade до WebSocket, таймаут соединения — 24 часа
- Максимальный размер загружаемых файлов через nginx — 50 МБ
- Auto-restart: если Node.js сервер упал, entrypoint перезапускает его через 1 секунду
- Чистое завершение (exit 0, SIGTERM) — контейнер останавливается без перезапуска
Переменные окружения
Сервер
| Переменная | По умолчанию | Описание |
|---|---|---|
PORT |
8080 |
Порт WebSocket сервера |
MAX_FILE_SIZE |
10485760 (10 МБ) |
Максимальный размер файла в байтах |
USERS_FILE |
users.json |
Путь к файлу с пользователями |
$env:PORT=9090; $env:MAX_FILE_SIZE=2097152; node server.js
Клиент
| Переменная | По умолчанию (dev) | По умолчанию (production) | Описание |
|---|---|---|---|
VITE_WS_URL |
ws://localhost:8080 |
/ws |
URL WebSocket сервера |
Настройки в client/.env.development (dev) и client/.env (production).
Протокол обмена
Аутентификация
// → сервер
{ "type": "auth", "login": "alice", "password": "123" }
// ← ответ
{ "type": "auth_result", "success": true }
{ "type": "auth_result", "success": false, "reason": "Invalid login or password" }
Текстовое сообщение
// → сервер
{ "type": "text", "text": "Привет!" }
// ← всем
{ "type": "text", "from": "alice", "timestamp": 1717000000000, "text": "Привет!" }
Файл / изображение / аудио / видео
// → сервер
{ "type": "file", "filename": "cat.png", "mime": "image/png", "data": "<base64>" }
// ← всем (от сервера добавлены from и timestamp)
{ "type": "file", "from": "alice", "timestamp": 1717000000000, "filename": "cat.png", "mime": "image/png", "data": "<base64>" }
Клиент определяет тип файла по MIME: image/* — картинка, audio/* — плеер, video/* — плеер, остальное — скачивание.
Системные сообщения
{ "type": "system", "text": "alice joined the chat" }
{ "type": "system", "text": "alice left the chat" }
Функциональность
- Текстовые сообщения — логин отправителя, время, ссылки (http/https) автоматически становятся кликабельными
- Файлы — любые типы, до 10 МБ (настраивается), base64 в JSON
- Изображения —
image/*→<img>, клик открывает в новой вкладке - Аудио —
audio/*→<audio controls>+ ссылка скачивания - Видео —
video/*→<video>с controls + ссылка скачивания - Голосовые сообщения — кнопка микрофона, запись через
MediaRecorder, отправка как файл - Уведомления — звук (Web Audio API) и красная точка на favicon при сообщении на неактивной вкладке
- Системные сообщения — подключение/отключение участников
- Автоскролл — кастомный тонкий скроллбар
- Вставка изображений из буфера обмена — Ctrl+V в поле ввода, отправка как файл
- Авто-переподключение — при разрыве WebSocket клиент автоматически пересоздаёт соединение
- Сохранение учётных данных — логин и пароль сохраняются в
localStorage, при повторном входе поле не требуется - Сохранение истории — последние 50 сообщений (текст, файлы) сохраняются в
localStorage - Закреплённые сообщения — любое сообщение можно закрепить в шапке чата
Структура проекта
chat/
├── server/
│ ├── config.js # Настройки из env
│ ├── auth.js # Загрузка пользователей, authenticate()
│ ├── clients.js # Управление соединениями, broadcast()
│ ├── server.js # Точка входа, WebSocketServer
│ ├── users.json # Хардкоженые логины/пароли
│ └── package.json
├── client/
│ ├── src/
│ │ ├── App.jsx / .css
│ │ ├── main.jsx
│ │ ├── hooks/
│ │ │ ├── useWebSocket.js # WebSocket + auth
│ │ │ └── useChatMessages.js # Приём сообщений + уведомления
│ │ ├── utils/
│ │ │ ├── blob.js # base64 → Blob URL
│ │ │ ├── linkify.jsx # URL → React-ссылки
│ │ │ └── notify.js # Звук + favicon
│ │ └── components/
│ │ ├── Login.jsx / .css
│ │ ├── Chat.jsx / .css
│ │ ├── MessageList.jsx
│ │ ├── Message.jsx / .css
│ │ ├── MessageInput.jsx / .css
│ │ └── VoiceRecorder.jsx / .css
│ ├── .env # Production настройки
│ ├── .env.development # Dev настройки
│ ├── index.html
│ ├── vite.config.js
│ └── package.json
├── Dockerfile # Многостадийная сборка
├── docker-entrypoint.sh # Auto-restart при падении
├── nginx.conf
├── .dockerignore
├── .gitignore
├── LICENSE
└── README.md
Languages
JavaScript
77.2%
CSS
18.8%
Dockerfile
1.9%
Shell
1.4%
HTML
0.7%