230 lines
6.9 KiB
Markdown
230 lines
6.9 KiB
Markdown
# cards
|
||
|
||
Веб-сервер на C++20 с использованием Boost.Beast и PostgreSQL. Отдаёт случайные записи из таблицы `random_data` по HTTP API.
|
||
|
||
## Требования
|
||
|
||
- Компилятор с поддержкой C++20 (GCC 10+, Clang 10+)
|
||
- CMake >= 3.14
|
||
- PostgreSQL (runtime) + libpq + libpqxx >= 7.0
|
||
- Boost (system)
|
||
- nlohmann_json 3.x
|
||
|
||
Установка зависимостей (Debian/Ubuntu):
|
||
|
||
```bash
|
||
sudo apt-get install libboost-all-dev libpq-dev libpqxx-dev nlohmann-json3-dev cmake build-essential
|
||
```
|
||
|
||
## Сборка
|
||
|
||
```bash
|
||
./configure.sh
|
||
```
|
||
|
||
Скрипт устанавливает зависимости для Debian/Ubuntu, собирает проект и создаёт deb-пакет.
|
||
|
||
Или вручную:
|
||
|
||
```bash
|
||
mkdir -p build && cd build
|
||
cmake ..
|
||
make -j"$(nproc)"
|
||
cd ..
|
||
```
|
||
|
||
Бинарник: `build/bin/cards`
|
||
|
||
## Конфигурация
|
||
|
||
По умолчанию читает `config.json` из рабочей директории. Можно указать путь к другому файлу:
|
||
|
||
```bash
|
||
./build/bin/cards /path/to/config.json
|
||
```
|
||
|
||
Для подробного вывода этапов запуска и итоговой конфигурации используйте флаг `--debug`. Он также включает диагностику работы с БД: создание схемы, запуск и остановку воркеров, запросы, выбранную стратегию выборки, результаты и переподключения после ошибок. Пароль базы данных в таком выводе не раскрывается.
|
||
|
||
```bash
|
||
./build/bin/cards --debug
|
||
./build/bin/cards --debug /path/to/config.json
|
||
```
|
||
|
||
Аргументы можно передавать в любом порядке. Программа принимает не более одного пути к файлу конфигурации.
|
||
|
||
### Поля `config.json`
|
||
|
||
**server**
|
||
| Поле | Тип | Обязательно |
|
||
|---|---|---|
|
||
| address | string | да |
|
||
| port | int | да |
|
||
| threads | int | да |
|
||
|
||
**database**
|
||
| Поле | Тип | Значение по умолчанию |
|
||
|---|---|---|
|
||
| host | string | `"localhost"` |
|
||
| port | int | `5432` |
|
||
| dbname | string | пустая строка |
|
||
| user | string | пустая строка |
|
||
| password | string | (пусто) |
|
||
|
||
### Переменные окружения
|
||
|
||
Переопределяют соответствующие поля `config.json`:
|
||
|
||
- `DB_HOST`
|
||
- `DB_PORT`
|
||
- `DB_NAME`
|
||
- `DB_USER`
|
||
- `DB_PASSWORD`
|
||
|
||
Пример:
|
||
|
||
```bash
|
||
DB_PASSWORD=secret ./build/bin/cards
|
||
```
|
||
|
||
## API
|
||
|
||
| Метод | Путь | Описание |
|
||
|---|---|---|
|
||
| GET | `/` | Случайная запись из таблицы `random_data` |
|
||
| GET | `/cards?count=N` | До `N` случайных записей из таблицы `random_data` |
|
||
| GET | `/health` | Проверка состояния сервера |
|
||
|
||
Параметр `count` обязателен для `/cards`, должен быть целым числом и ограничивается диапазоном от 1 до 1000. Если записей в базе меньше запрошенного числа, сервер вернёт все доступные записи. Для выборок до 10 записей применяется обычная стратегия, для бо́льших — рекурсивный SQL-запрос.
|
||
|
||
### Пример ответа `GET /`
|
||
|
||
```json
|
||
{
|
||
"id": 3,
|
||
"name": "Gamma",
|
||
"text": "Third test record",
|
||
"description": "Third test record",
|
||
"created_at": "2025-01-01 12:00:00",
|
||
"timestamp": 1735732800000000000
|
||
}
|
||
```
|
||
|
||
### Пример ответа `GET /cards?count=2`
|
||
|
||
```json
|
||
{
|
||
"data": [
|
||
{
|
||
"id": 3,
|
||
"name": "Gamma",
|
||
"text": "Third test record",
|
||
"description": "Third test record",
|
||
"created_at": "2025-01-01 12:00:00"
|
||
},
|
||
{
|
||
"id": 5,
|
||
"name": "Delta",
|
||
"text": "Fourth test record",
|
||
"description": "Fourth test record",
|
||
"created_at": "2025-01-01 12:00:00"
|
||
}
|
||
],
|
||
"count": 2,
|
||
"requested_count": 2,
|
||
"total_available": 5,
|
||
"strategy": "slow",
|
||
"timestamp": 1735732800000000000
|
||
}
|
||
```
|
||
|
||
### Пример ответа `GET /health`
|
||
|
||
```json
|
||
{
|
||
"status": "ok",
|
||
"timestamp": 1735732800000000000
|
||
}
|
||
```
|
||
|
||
## База данных
|
||
|
||
При первом запуске автоматически создаётся таблица `random_data`. Начальные данные сервер не добавляет: их необходимо загрузить самостоятельно.
|
||
|
||
Схема таблицы:
|
||
|
||
```sql
|
||
CREATE TABLE random_data (
|
||
id SERIAL PRIMARY KEY,
|
||
name VARCHAR(100) NOT NULL,
|
||
text TEXT NOT NULL,
|
||
description TEXT,
|
||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||
);
|
||
```
|
||
|
||
> При обновлении существующей базы данных схему нужно мигрировать отдельно: `CREATE TABLE IF NOT EXISTS` не изменяет уже созданные таблицы. Например, для предыдущей схемы с полем `value` выполните `ALTER TABLE random_data RENAME COLUMN value TO text;`.
|
||
|
||
## systemd
|
||
|
||
Юнит-файл: `deploy/systemd/cards.service`
|
||
|
||
```ini
|
||
[Unit]
|
||
Description=Cards web server
|
||
After=network-online.target
|
||
|
||
[Service]
|
||
Type=simple
|
||
User=cards
|
||
Group=cards
|
||
ExecStart=/usr/bin/cards /etc/cards/config.json
|
||
Restart=on-failure
|
||
AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||
NoNewPrivileges=yes
|
||
ProtectSystem=full
|
||
ProtectHome=yes
|
||
PrivateTmp=yes
|
||
```
|
||
|
||
Установка вручную:
|
||
|
||
```bash
|
||
sudo cp deploy/systemd/cards.service /usr/lib/systemd/system/
|
||
sudo systemctl daemon-reload
|
||
sudo systemctl enable --now cards
|
||
```
|
||
|
||
## Сборка deb-пакета
|
||
|
||
```bash
|
||
cd build
|
||
cmake ..
|
||
cpack
|
||
```
|
||
|
||
Результат: `cards-1.0.1-Linux.deb`
|
||
|
||
### Содержимое deb-пакета
|
||
|
||
| Путь | Назначение |
|
||
|---|---|
|
||
| `/usr/bin/cards` | Исполняемый файл |
|
||
| `/usr/lib/systemd/system/cards.service` | systemd-юнит |
|
||
| `/etc/cards/config.json.example` | Пример конфигурации |
|
||
| `/usr/share/doc/cards/LICENSE` | Лицензия |
|
||
|
||
### Управляющие скрипты
|
||
|
||
При установке deb-пакета (`postinst`):
|
||
- Создаётся пользователь и группа `cards`
|
||
- Копируется `/etc/cards/config.json.example` → `/etc/cards/config.json` (если нет)
|
||
- Сервис `cards` включается и запускается
|
||
|
||
При удалении (`prerm`):
|
||
- Сервис останавливается и отключается
|
||
|
||
## Завершение работы
|
||
|
||
- Вручную: `Ctrl+C` или `kill` с сигналом `SIGTERM`
|
||
- systemd: `systemctl stop cards`
|