Refactor VPN configuration handling to remove device limit management
- Updated the VPN configuration commands and handlers to eliminate the device limit parameter, simplifying the configuration process. - Adjusted related API documentation to reflect the removal of device limit management, clarifying that this setting is now handled directly in the 3x-ui by node administrators. - Enhanced the overall codebase by removing unnecessary device limit references across various components, ensuring a cleaner and more maintainable code structure.
This commit is contained in:
+3
-3
@@ -65,15 +65,15 @@ rate-limit'ом (`RateLimiting:AuthPermitLimit`, по умолчанию 20 за
|
||||
| ------ | --------------------------------- | ------------------------------------ | --------------------------------------- |
|
||||
| GET | `/api/inbounds/available` | — | `AvailableInboundDto[]` |
|
||||
| GET | `/api/configs` | — | `{ configs: VpnConfigDto[], maxConfigs }` — **без пагинации**, весь список сразу |
|
||||
| POST | `/api/configs` | `{ inboundId, label?, deviceLimit? }`| `VpnConfigDto` (`200 OK`, не 201) |
|
||||
| PATCH | `/api/configs/{id}` | `{ label?, deviceLimit? }` | `VpnConfigDto` |
|
||||
| POST | `/api/configs` | `{ inboundId, label? }` | `VpnConfigDto` (`200 OK`, не 201) |
|
||||
| PATCH | `/api/configs/{id}` | `{ label? }` | `VpnConfigDto` |
|
||||
| POST | `/api/configs/{id}/rotate` | — | `VpnConfigDto` (новый `id` тот же, новый `SubscriptionToken`) |
|
||||
| DELETE | `/api/configs/{id}` | — | `204 No Content` |
|
||||
| GET | `/api/configs/{id}/link` | — | `{ connectionString, subscriptionUrl }` |
|
||||
| GET | `/api/subscription` | — | `{ subscriptionUrl }` |
|
||||
|
||||
**Нет отдельного `GET /api/configs/{id}`** — детали конфига берутся из списка `GET /api/configs`.
|
||||
`VpnConfigDto`: `{ id, label, protocol, location, deviceLimit, usedUpBytes, usedDownBytes, expiresAt,
|
||||
`VpnConfigDto`: `{ id, label, protocol, location, usedUpBytes, usedDownBytes, expiresAt,
|
||||
status, createdAt }`. `expiresAt` всегда `null` (лимиты по сроку не реализованы — см.
|
||||
[domain-model.md](domain-model.md)). Ссылка подключения **не приходит вместе с созданием** — фронт
|
||||
запрашивает `GET .../link` отдельно, по кнопке на карточке конфига; QR строится на фронте из
|
||||
|
||||
@@ -132,7 +132,7 @@ PnvPanel — backend на **ASP.NET Core (.NET 10)** по принципам **C
|
||||
```
|
||||
POST /api/configs
|
||||
→ CreateVpnConfigCommand
|
||||
→ ValidationBehavior (FluentValidation — формат inboundId/label/deviceLimit)
|
||||
→ ValidationBehavior (FluentValidation — формат inboundId/label)
|
||||
→ CreateVpnConfigCommandHandler
|
||||
· проверяет активацию + роль инбаунда (доменные проверки)
|
||||
· SELECT pg_advisory_xact_lock(hashtext(userId)) — сериализует параллельные создания
|
||||
@@ -141,7 +141,7 @@ POST /api/configs
|
||||
· VpnConfig.Create(...) + AssignRemoteClient(id), сохраняет через IAppDbContext
|
||||
· при сбое SaveChanges после успешного AddClientAsync — компенсация (RemoveClientAsync)
|
||||
→ UnitOfWorkBehavior (commit транзакции)
|
||||
→ 200 OK VpnConfigDto { id, label, protocol, location, deviceLimit, usedUpBytes, usedDownBytes,
|
||||
→ 200 OK VpnConfigDto { id, label, protocol, location, usedUpBytes, usedDownBytes,
|
||||
expiresAt, status, createdAt }
|
||||
```
|
||||
Ссылка подключения в ответ создания **не входит** — фронт запрашивает её отдельно,
|
||||
|
||||
@@ -80,7 +80,6 @@ ClientApp (каталог приложений-клиен
|
||||
| `ClientEmail` | `string` | Уникальный ключ клиента в 3x-ui; схема `pnv_{userIdShort}_{rand}` (уникален в рамках панели, виден владелец) |
|
||||
| `ClientExternalId` | `string` | Идентификатор клиента, который вернула панель (UUID для VLESS/VMess, пароль для Trojan/Shadowsocks — ThreeXui.Net отдаёт его как string) |
|
||||
| `Protocol` | `VpnProtocol` | Денормализовано с inbound |
|
||||
| `DeviceLimit` | `int` | Лимит одновременных устройств/IP (0 = без лимита); задаёт юзер → `limitIp` в 3x-ui |
|
||||
| `UsedUpBytes` | `long` | Синхронизируется из 3x-ui (только для отображения — лимит трафика не применяется) |
|
||||
| `UsedDownBytes` | `long` | Синхронизируется из 3x-ui |
|
||||
| `ExpiresAt` | `DateTimeOffset?`| Зарезервировано, сейчас ничего его не выставляет — конфиг живёт бессрочно |
|
||||
@@ -100,7 +99,8 @@ ClientApp (каталог приложений-клиен
|
||||
удаляет старого, генерирует новый `SubscriptionToken`; квоту **не тратит**. Для случая утечки ссылки.
|
||||
- `Disable()`/`Enable()` → меняют только статус записи (`Active ↔ Disabled`); отключение/включение
|
||||
самого клиента в 3x-ui делает хендлер отдельным вызовом гейтвея (используется при блокировке юзера).
|
||||
- `Rename(label)` / `SetDeviceLimit(n)` → юзер меняет метку и лимит устройств (последнее синкается в `limitIp` 3x-ui).
|
||||
- `Rename(label)` → юзер меняет метку (синкается в 3x-ui как имя клиента). Лимит устройств/IP (`limitIp`
|
||||
в 3x-ui) панелью не управляется — более сложная per-node настройка, задаётся напрямую в 3x-ui администратором.
|
||||
- `UpdateTraffic(up, down)` → пишет `TrafficSyncService` при периодической синхронизации, только для отображения.
|
||||
- **Создание разрешено только активированному пользователю** (`AppUser.IsActivated == true`).
|
||||
- Число активных конфигов пользователя не может превышать **квоту его роли** (`AppRole.MaxConfigs`;
|
||||
|
||||
+5
-3
@@ -87,10 +87,12 @@ frontend/
|
||||
трафик, статус), кнопки на карточке — показать ссылку/QR (запрашивает `GET .../link` по клику,
|
||||
не сразу при создании), перевыпустить, отозвать; отдельная карточка «Общая подписка». Для
|
||||
неактивированного — `ActivationGate` вместо дашборда.
|
||||
- **Создание конфига**: диалог — выбор инбаунда (по `displayName`) + метка + лимит устройств.
|
||||
После успеха карточка конфига появляется в списке; ссылку/QR пользователь открывает отдельно.
|
||||
- **Создание конфига**: диалог — выбор инбаунда (по `displayName`) + метка. Лимит устройств
|
||||
(`limitIp` в 3x-ui) панелью не управляется — задаётся при необходимости напрямую в 3x-ui. После
|
||||
успеха карточка конфига появляется в списке; ссылку/QR пользователь открывает отдельно.
|
||||
- **Страница инструкций** (`/instructions`): статичные шаги + каталог приложений (`GET /api/apps`),
|
||||
сгруппированный по ОС; клик по приложению открывает ссылку на скачивание.
|
||||
сгруппированный по ОС и показан вкладками (по одной ОС за раз); клик по приложению открывает
|
||||
ссылку на скачивание.
|
||||
- **Настройки** (`/settings`): смена пароля, привязка/отвязка Telegram (`TelegramLinkCard`),
|
||||
удаление аккаунта с подтверждением (`DeleteAccountSection`).
|
||||
- **Админка** (`/admin/*`): вкладки — обзор (карточки статистики, без графиков), запросы активации,
|
||||
|
||||
+1
-1
@@ -92,8 +92,8 @@
|
||||
| Подписка | Агрегированная на юзера (`AppUser.SubscriptionToken`) + по конфигу |
|
||||
| Аудит | `AuditLog` (append-only): активация, блокировка, смена роли, отзыв, ноды/инбаунды |
|
||||
| Ротация конфига | `Rotate()` — перевыпуск UUID/ссылки, квоту не тратит (на случай утечки) |
|
||||
| Лимит устройств | Per-config, задаёт юзер (`DeviceLimit` → `limitIp` в 3x-ui; 0 = без лимита) |
|
||||
| Метка конфига | `Label` — пользователь именует конфиг («Мой телефон») |
|
||||
| Лимит устройств (`limitIp`) | Панелью не управляется — задаётся при необходимости напрямую в 3x-ui администратором ноды |
|
||||
| Самоудаление аккаунта | Отзыв всех активных конфигов в 3x-ui + удаление `AppUser` |
|
||||
| Версионирование API | Без версий (`/api` без `v1`) |
|
||||
| Подписка (заголовки) | `Subscription-Userinfo` (used/total/expire) + `profile-update-interval` |
|
||||
|
||||
Reference in New Issue
Block a user