using PnvPanel.Api.Common; using PnvPanel.Application.Common.Messaging; using PnvPanel.Application.Configs; using PnvPanel.Application.Configs.Create; using PnvPanel.Application.Configs.Edit; using PnvPanel.Application.Configs.GetConfigLink; using PnvPanel.Application.Configs.GetMyConfigs; using PnvPanel.Application.Configs.GetMySubscription; using PnvPanel.Application.Configs.ListAvailableInbounds; using PnvPanel.Application.Configs.Revoke; using PnvPanel.Application.Configs.Rotate; namespace PnvPanel.Api.Endpoints; public static class ConfigEndpoints { public static IEndpointRouteBuilder MapConfigEndpoints(this IEndpointRouteBuilder app) { var group = app.MapGroup("/api").WithTags("Configs").RequireAuthorization(); group.MapGet("/inbounds/available", ListAvailableInbounds).Produces>(); group.MapGet("/configs", GetMyConfigs).Produces(); group.MapPost("/configs", CreateConfig).Produces(); group.MapPatch("/configs/{id:guid}", EditConfig).Produces(); group.MapPost("/configs/{id:guid}/rotate", RotateConfig).Produces(); group.MapDelete("/configs/{id:guid}", RevokeConfig).Produces(StatusCodes.Status204NoContent); group.MapGet("/configs/{id:guid}/link", GetConfigLink).Produces(); group.MapGet("/subscription", GetMySubscription).Produces(); return app; } private static async Task ListAvailableInbounds(ISender sender, CancellationToken cancellationToken) { var result = await sender.Send(new ListAvailableInboundsQuery(), cancellationToken); return result.ToHttpResult(); } private static async Task GetMyConfigs(ISender sender, CancellationToken cancellationToken) { var result = await sender.Send(new GetMyConfigsQuery(), cancellationToken); return result.ToHttpResult(); } private static async Task CreateConfig(CreateConfigBody body, ISender sender, CancellationToken cancellationToken) { var command = new CreateVpnConfigCommand(body.InboundId, body.Label, body.DeviceLimit); var result = await sender.Send(command, cancellationToken); return result.ToHttpResult(); } private static async Task EditConfig(Guid id, EditConfigBody body, ISender sender, CancellationToken cancellationToken) { var command = new EditVpnConfigCommand(id, body.Label, body.DeviceLimit); var result = await sender.Send(command, cancellationToken); return result.ToHttpResult(); } private static async Task RotateConfig(Guid id, ISender sender, CancellationToken cancellationToken) { var result = await sender.Send(new RotateVpnConfigCommand(id), cancellationToken); return result.ToHttpResult(); } private static async Task RevokeConfig(Guid id, ISender sender, CancellationToken cancellationToken) { var result = await sender.Send(new RevokeVpnConfigCommand(id), cancellationToken); return result.ToHttpResult(); } private static async Task GetConfigLink(Guid id, HttpRequest request, ISender sender, CancellationToken cancellationToken) { var result = await sender.Send(new GetConfigLinkQuery(id), cancellationToken); if (!result.IsSuccess) return result.ToHttpResult(); var subscriptionUrl = $"{request.Scheme}://{request.Host}/sub/{result.Value.SubscriptionToken}"; return Results.Ok(new ConfigLinkResponseDto(result.Value.ConnectionString, subscriptionUrl)); } private static async Task GetMySubscription(HttpRequest request, ISender sender, CancellationToken cancellationToken) { var result = await sender.Send(new GetMySubscriptionQuery(), cancellationToken); if (!result.IsSuccess) return result.ToHttpResult(); var subscriptionUrl = $"{request.Scheme}://{request.Host}/sub/{result.Value.SubscriptionToken}"; return Results.Ok(new MySubscriptionResponseDto(subscriptionUrl)); } } public sealed record CreateConfigBody(Guid InboundId, string? Label, int? DeviceLimit); public sealed record EditConfigBody(string? Label, int? DeviceLimit); public sealed record ConfigLinkResponseDto(string ConnectionString, string SubscriptionUrl); public sealed record MySubscriptionResponseDto(string SubscriptionUrl);