Add IsAvailable property to Inbound and update related logic
CI / Backend (build + test) (push) Successful in 1m19s
CI / Frontend (lint + typecheck + build) (push) Successful in 35s

- Introduced a new boolean property, `IsAvailable`, to the `Inbound` entity to track the availability status of inbounds based on synchronization results.
- Updated the `SyncNodeCommandHandler` to mark inbounds as unavailable if they are not present in the latest synchronization but have existing configurations, preventing their deletion.
- Enhanced the `MarkUnavailable` method to set both `IsAvailable` and `IsPublished` to false, reflecting the new status accurately.
- Modified the frontend components to display the availability status of inbounds, ensuring users are informed of their current state.
- Updated tests to cover the new behavior regarding inbound availability and its impact on revocation processes.
This commit is contained in:
Leonid Pershin
2026-07-19 00:13:30 +03:00
parent c196e0c322
commit b980dc6cef
16 changed files with 1211 additions and 14 deletions
+3
View File
@@ -170,6 +170,9 @@ POST /api/configs
к ноде. Cookie-session и авто-переавторизация на 401 обеспечиваются самой `ThreeXui.Net`.
- Ошибки панели маппятся в доменные/`Result`-ошибки; недоступная нода → `NodeStatus.Offline`, а не исключение наружу.
- Операции мутации по клиентам сериализуются per-inbound (библиотека уже использует мьютексы; на нашей стороне — идемпотентные команды).
- Синхронизация инбаундов ноды (`SyncNodeCommandHandler`) реконсилирует пропажу инбаунда с панели:
без привязанных конфигов запись удаляется, с конфигами — помечается `IsAvailable=false` (детали и
инварианты — [domain-model.md](domain-model.md#inbound--прокси-inbound-на-ноде)).
- `BuildConnectionStringAsync` поверх ссылки из `ThreeXui.Net` принудительно подставляет
`fp=firefox` (TLS-fingerprint клиента) для tls/reality-ссылок vless/trojan/vmess, независимо
от того, что задано в `streamSettings` ноды; shadowsocks (без TLS) и ссылки без security не
+9
View File
@@ -64,6 +64,7 @@ AppUser
| `Remark` | `string` | Метка из 3x-ui |
| `Port` | `int` | |
| `IsPublished` | `bool` | Доступен ли для самообслуживания пользователями |
| `IsAvailable` | `bool` | Существует ли инбаунд на панели по последней синхронизации (см. ниже) |
| `AllowedRoleIds` | `Guid[]` | Id ролей, которым разрешено создавать конфиги (native PostgreSQL `uuid[]`; не навигация на `AppRole` — тот в Infrastructure/Identity, Domain на него не ссылается) |
| `DisplayName` | `string?` | Витринное имя для пользователя, напр. «Германия (Trojan)» |
| `LastSyncAt` | `DateTimeOffset?` | |
@@ -73,6 +74,14 @@ AppUser
«Германия (Trojan)» → роли `user`, `vip`). Лимита числа клиентов на инбаунд нет — квота
ограничивается только на уровне пользователя (`AppRole.MaxConfigs`).
**Синхронизация и пропажа инбаунда с панели** (`SyncNodeCommandHandler`, кнопка «Синхронизировать»):
инбаунд, не пришедший в очередном ответе 3x-ui, считается пропавшим. Если по нему нет ни одного
`VpnConfig` — запись просто удаляется (иначе при пересоздании того же инбаунда на панели под новым
`RemoteInboundId` — 3x-ui не переиспользует id — накапливался бы визуальный дубль). Если конфиги
есть — удалить нельзя (FK), инбаунд помечается `MarkUnavailable()` (`IsAvailable=false`,
`IsPublished=false`): новые конфиги на нём не создать, а `Revoke` для существующих конфигов не бьёт
в панель повторно (см. `RevokeVpnConfigCommandHandler`), а отзывает локально.
> `Node.Status` (health-check раз в 2 минуты, см. `NodeHealthCheckService`) — это диагностический
> индикатор для админа, не гейт для создания конфига: он кэшированный и может ложно показывать
> `Offline` из-за временного сбоя пробника. Реальную недоступность ноды ловит вызов