Files
min-chat/README.md
T
Комаров Данил Анатольевич 6 199a3ea2fe Обновлён README, добавлена лицензия MIT
2026-05-29 16:42:32 +03:00

193 lines
7.7 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.
Текстовые сообщения, файлы, изображения, аудио, видео и голосовые сообщения.
**Сервер:** 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 .
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` | Путь к файлу с пользователями |
```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` (dev) и `client/.env` (production).
---
## Протокол обмена
### Аутентификация
```json
// → сервер
{ "type": "auth", "login": "alice", "password": "123" }
// ← ответ
{ "type": "auth_result", "success": true }
{ "type": "auth_result", "success": false, "reason": "Invalid login or password" }
```
### Текстовое сообщение
```json
// → сервер
{ "type": "text", "text": "Привет!" }
// ← всем
{ "type": "text", "from": "alice", "timestamp": 1717000000000, "text": "Привет!" }
```
### Файл / изображение / аудио / видео
```json
// → сервер
{ "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/*` — плеер, остальное — скачивание.
### Системные сообщения
```json
{ "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
```