Refactor VPN config creation logic to improve node status handling
- Removed the dependency on `Node.Status` for VPN config creation, addressing potential false negatives due to cached health-check data. - Updated documentation to clarify that `Node.Status` is a diagnostic indicator and not a gate for config creation, ensuring accurate understanding of node availability checks. - Enhanced comments in the code to explain the rationale behind the changes, improving maintainability and clarity for future developers.
This commit is contained in:
@@ -4,7 +4,6 @@ using PnvPanel.Application.Common.Interfaces;
|
|||||||
using PnvPanel.Application.Common.Messaging;
|
using PnvPanel.Application.Common.Messaging;
|
||||||
using PnvPanel.Application.Common.Models;
|
using PnvPanel.Application.Common.Models;
|
||||||
using PnvPanel.Domain.Configs;
|
using PnvPanel.Domain.Configs;
|
||||||
using PnvPanel.Domain.Nodes;
|
|
||||||
|
|
||||||
namespace PnvPanel.Application.Configs.Create;
|
namespace PnvPanel.Application.Configs.Create;
|
||||||
|
|
||||||
@@ -40,7 +39,11 @@ public sealed class CreateVpnConfigCommandHandler(
|
|||||||
var node = await dbContext
|
var node = await dbContext
|
||||||
.Nodes.AsNoTracking()
|
.Nodes.AsNoTracking()
|
||||||
.FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
|
.FirstOrDefaultAsync(n => n.Id == inbound.NodeId, cancellationToken);
|
||||||
if (node is null || !node.IsEnabled || node.Status == NodeStatus.Offline)
|
// Node.Status — это кэш периодического health-check'а (раз в 2 минуты), а не проверка
|
||||||
|
// в реальном времени: блокировать по нему создание конфига значит ловить ложные отказы на
|
||||||
|
// временных сетевых сбоях пробника. Реальную недоступность ловит AddClientAsync ниже —
|
||||||
|
// тот бьёт в панель прямо сейчас и возвращает честную ошибку с компенсацией.
|
||||||
|
if (node is null || !node.IsEnabled)
|
||||||
return Result.Failure<VpnConfigDto>(ConfigErrors.NodeDisabled);
|
return Result.Failure<VpnConfigDto>(ConfigErrors.NodeDisabled);
|
||||||
|
|
||||||
var config = VpnConfig.Create(userId, inbound.Id, inbound.Protocol, command.Label);
|
var config = VpnConfig.Create(userId, inbound.Id, inbound.Protocol, command.Label);
|
||||||
|
|||||||
+10
-4
@@ -65,10 +65,16 @@ AppUser
|
|||||||
| `DisplayName` | `string?` | Витринное имя для пользователя, напр. «Германия (Trojan)» |
|
| `DisplayName` | `string?` | Витринное имя для пользователя, напр. «Германия (Trojan)» |
|
||||||
| `LastSyncAt` | `DateTimeOffset?` | |
|
| `LastSyncAt` | `DateTimeOffset?` | |
|
||||||
|
|
||||||
Инварианты: конфиг можно создать только если `IsPublished && Node.IsEnabled && Node.Status !=
|
Инварианты: конфиг можно создать только если `IsPublished && Node.IsEnabled`, и **роль пользователя
|
||||||
Offline`, и **роль пользователя входит в `AllowedRoles`**. Публикация инбаунда админом включает
|
входит в `AllowedRoles`**. Публикация инбаунда админом включает выбор `AllowedRoles` (напр.
|
||||||
выбор `AllowedRoles` (напр. «Германия (Trojan)» → роли `user`, `vip`). Лимита числа клиентов на
|
«Германия (Trojan)» → роли `user`, `vip`). Лимита числа клиентов на инбаунд нет — квота
|
||||||
инбаунд нет — квота ограничивается только на уровне пользователя (`AppRole.MaxConfigs`).
|
ограничивается только на уровне пользователя (`AppRole.MaxConfigs`).
|
||||||
|
|
||||||
|
> `Node.Status` (health-check раз в 2 минуты, см. `NodeHealthCheckService`) — это диагностический
|
||||||
|
> индикатор для админа, не гейт для создания конфига: он кэшированный и может ложно показывать
|
||||||
|
> `Offline` из-за временного сбоя пробника. Реальную недоступность ноды ловит вызов
|
||||||
|
> `IXuiPanelGateway.AddClientAsync` в момент создания — с честной ошибкой и компенсацией
|
||||||
|
> зарезервированной квоты, а не заранее закэшированным статусом.
|
||||||
|
|
||||||
> **Пользователю показываем только `DisplayName` + протокол.** Адрес/хост ноды, `RemoteInboundId`,
|
> **Пользователю показываем только `DisplayName` + протокол.** Адрес/хост ноды, `RemoteInboundId`,
|
||||||
> `Port` и прочие детали 3x-ui в пользовательские DTO не попадают (только в админские).
|
> `Port` и прочие детали 3x-ui в пользовательские DTO не попадают (только в админские).
|
||||||
|
|||||||
Reference in New Issue
Block a user