# Чат с общей комнатой Веб-приложение чата с одной общей комнатой на WebSocket. Поддерживает текстовые сообщения, отправку файлов и отображение изображений. **Сервер:** Node.js + `ws` **Клиент:** React + Vite **Прокси:** nginx (production-сборка) --- ## Быстрый запуск (разработка) ### Сервер ```bash cd server npm install npm start ``` Запускает WebSocket сервер на `ws://localhost:8080`. ### Клиент ```bash cd client npm install npx vite ``` Запускает dev-сервер на `http://localhost:3000`. В режиме разработки клиент подключается напрямую к `ws://localhost:8080`. ### Пользователи по умолчанию | Логин | Пароль | |-------|--------| | alice | 123 | | bob | 456 | --- ## Production (Docker) ### Сборка образа ```bash docker build -t chat-app . ``` ### Запуск контейнера ```bash docker run -d -p 80:80 chat-app ``` Открой `http://localhost`. ### Как это работает - **nginx** на порту 80 раздаёт статику React и проксирует WebSocket - Путь `/` → статические файлы клиента (`index.html`, JS, CSS) - Путь `/ws` → прокси на Node.js WebSocket сервер (порт 8080 внутри контейнера) - nginx поддерживает Upgrade до WebSocket, таймаут соединения — 24 часа - Максимальный размер загружаемых файлов через nginx — 50 МБ - После остановки Node.js контейнер завершается (через `wait`) --- ## Переменные окружения ### Сервер | Переменная | По умолчанию | Описание | |-----------|-------------|---------| | `PORT` | `8080` | Порт WebSocket сервера | | `MAX_FILE_SIZE` | `10485760` (10 МБ) | Максимальный размер файла в байтах | | `USERS_FILE` | `users.json` | Путь к файлу с пользователями | Пример: ```bash $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` — для `npx vite` (dev-режим) - `client/.env` — для `vite build` (production-сборка) --- ## Протокол обмена ### Аутентификация Клиент → Сервер: ```json { "type": "auth", "login": "alice", "password": "123" } ``` Сервер → Клиент: ```json { "type": "auth_result", "success": true } ``` ```json { "type": "auth_result", "success": false, "reason": "Invalid login or password" } ``` ### Текстовое сообщение Клиент → Сервер: ```json { "type": "text", "text": "Привет!" } ``` Сервер → Все: ```json { "type": "text", "from": "alice", "timestamp": 1717000000000, "text": "Привет!" } ``` ### Файл / изображение Клиент → Сервер: ```json { "type": "file", "filename": "cat.png", "mime": "image/png", "data": "" } ``` Сервер → Все (такая же структура, добавлены `from` и `timestamp`): ```json { "type": "file", "from": "alice", "timestamp": 1717000000000, "filename": "cat.png", "mime": "image/png", "data": "" } ``` ### Системные сообщения Сервер → Все: ```json { "type": "system", "text": "alice joined the chat" } ``` --- ## Функциональность - **Текстовые сообщения** — отображаются с логином отправителя и временем - **Файлы** — любые типы, до 10 МБ (настраивается). Файлы передаются через base64 в JSON - **Изображения** — автоматически определяются по MIME-типу (`image/*`), рендерятся как ``, клик открывает в новой вкладке - **Не-изображения** — отображаются как ссылка для скачивания с именем файла - **Уведомления на неактивной вкладке** — звуковой сигнал (Web Audio API) и красная точка на favicon - **Системные сообщения** — подключение / отключение участников - **Скролл** — автоматический, кастомный тонкий скроллбар в теме приложения --- ## Структура проекта ``` chat/ ├── server/ │ ├── server.js # WebSocket сервер │ ├── users.json # Хардкоженые логины/пароли │ └── package.json ├── client/ │ ├── src/ │ │ ├── App.jsx # Корневой компонент │ │ ├── App.css │ │ ├── main.jsx # Точка входа │ │ └── components/ │ │ ├── Login.jsx / .css │ │ ├── Chat.jsx / .css │ │ ├── MessageList.jsx │ │ ├── Message.jsx / .css │ │ └── MessageInput.jsx / .css │ ├── .env # Production настройки │ ├── .env.development # Dev настройки │ ├── index.html │ ├── vite.config.js │ └── package.json ├── Dockerfile # Многостадийная сборка ├── docker-entrypoint.sh # Точка входа контейнера ├── nginx.conf # Конфигурация nginx └── README.md ```