209 lines
6.2 KiB
Markdown
209 lines
6.2 KiB
Markdown
# Чат с общей комнатой
|
|
|
|
Веб-приложение чата с одной общей комнатой на 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": "<base64>"
|
|
}
|
|
```
|
|
|
|
Сервер → Все (такая же структура, добавлены `from` и `timestamp`):
|
|
|
|
```json
|
|
{
|
|
"type": "file",
|
|
"from": "alice",
|
|
"timestamp": 1717000000000,
|
|
"filename": "cat.png",
|
|
"mime": "image/png",
|
|
"data": "<base64>"
|
|
}
|
|
```
|
|
|
|
### Системные сообщения
|
|
|
|
Сервер → Все:
|
|
|
|
```json
|
|
{ "type": "system", "text": "alice joined the chat" }
|
|
```
|
|
|
|
---
|
|
|
|
## Функциональность
|
|
|
|
- **Текстовые сообщения** — отображаются с логином отправителя и временем
|
|
- **Файлы** — любые типы, до 10 МБ (настраивается). Файлы передаются через base64 в JSON
|
|
- **Изображения** — автоматически определяются по MIME-типу (`image/*`), рендерятся как `<img>`, клик открывает в новой вкладке
|
|
- **Не-изображения** — отображаются как ссылка для скачивания с именем файла
|
|
- **Уведомления на неактивной вкладке** — звуковой сигнал (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
|
|
```
|