| package admin |
|
|
| import ( |
| "context" |
| "strconv" |
| "strings" |
|
|
| "github.com/Wei-Shaw/sub2api/internal/handler/dto" |
| "github.com/Wei-Shaw/sub2api/internal/pkg/response" |
| "github.com/Wei-Shaw/sub2api/internal/service" |
|
|
| "github.com/gin-gonic/gin" |
| ) |
|
|
| |
| type ProxyHandler struct { |
| adminService service.AdminService |
| } |
|
|
| |
| func NewProxyHandler(adminService service.AdminService) *ProxyHandler { |
| return &ProxyHandler{ |
| adminService: adminService, |
| } |
| } |
|
|
| |
| type CreateProxyRequest struct { |
| Name string `json:"name" binding:"required"` |
| Protocol string `json:"protocol" binding:"required,oneof=http https socks5 socks5h"` |
| Host string `json:"host" binding:"required"` |
| Port int `json:"port" binding:"required,min=1,max=65535"` |
| Username string `json:"username"` |
| Password string `json:"password"` |
| } |
|
|
| |
| type UpdateProxyRequest struct { |
| Name string `json:"name"` |
| Protocol string `json:"protocol" binding:"omitempty,oneof=http https socks5 socks5h"` |
| Host string `json:"host"` |
| Port int `json:"port" binding:"omitempty,min=1,max=65535"` |
| Username string `json:"username"` |
| Password string `json:"password"` |
| Status string `json:"status" binding:"omitempty,oneof=active inactive"` |
| } |
|
|
| |
| |
| func (h *ProxyHandler) List(c *gin.Context) { |
| page, pageSize := response.ParsePagination(c) |
| protocol := c.Query("protocol") |
| status := c.Query("status") |
| search := c.Query("search") |
| |
| search = strings.TrimSpace(search) |
| if len(search) > 100 { |
| search = search[:100] |
| } |
|
|
| proxies, total, err := h.adminService.ListProxiesWithAccountCount(c.Request.Context(), page, pageSize, protocol, status, search) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| out := make([]dto.AdminProxyWithAccountCount, 0, len(proxies)) |
| for i := range proxies { |
| out = append(out, *dto.ProxyWithAccountCountFromServiceAdmin(&proxies[i])) |
| } |
| response.Paginated(c, out, total, page, pageSize) |
| } |
|
|
| |
| |
| |
| func (h *ProxyHandler) GetAll(c *gin.Context) { |
| withCount := c.Query("with_count") == "true" |
|
|
| if withCount { |
| proxies, err := h.adminService.GetAllProxiesWithAccountCount(c.Request.Context()) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
| out := make([]dto.AdminProxyWithAccountCount, 0, len(proxies)) |
| for i := range proxies { |
| out = append(out, *dto.ProxyWithAccountCountFromServiceAdmin(&proxies[i])) |
| } |
| response.Success(c, out) |
| return |
| } |
|
|
| proxies, err := h.adminService.GetAllProxies(c.Request.Context()) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| out := make([]dto.AdminProxy, 0, len(proxies)) |
| for i := range proxies { |
| out = append(out, *dto.ProxyFromServiceAdmin(&proxies[i])) |
| } |
| response.Success(c, out) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) GetByID(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| proxy, err := h.adminService.GetProxy(c.Request.Context(), proxyID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, dto.ProxyFromServiceAdmin(proxy)) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) Create(c *gin.Context) { |
| var req CreateProxyRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| executeAdminIdempotentJSON(c, "admin.proxies.create", req, service.DefaultWriteIdempotencyTTL(), func(ctx context.Context) (any, error) { |
| proxy, err := h.adminService.CreateProxy(ctx, &service.CreateProxyInput{ |
| Name: strings.TrimSpace(req.Name), |
| Protocol: strings.TrimSpace(req.Protocol), |
| Host: strings.TrimSpace(req.Host), |
| Port: req.Port, |
| Username: strings.TrimSpace(req.Username), |
| Password: strings.TrimSpace(req.Password), |
| }) |
| if err != nil { |
| return nil, err |
| } |
| return dto.ProxyFromServiceAdmin(proxy), nil |
| }) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) Update(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| var req UpdateProxyRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| proxy, err := h.adminService.UpdateProxy(c.Request.Context(), proxyID, &service.UpdateProxyInput{ |
| Name: strings.TrimSpace(req.Name), |
| Protocol: strings.TrimSpace(req.Protocol), |
| Host: strings.TrimSpace(req.Host), |
| Port: req.Port, |
| Username: strings.TrimSpace(req.Username), |
| Password: strings.TrimSpace(req.Password), |
| Status: strings.TrimSpace(req.Status), |
| }) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, dto.ProxyFromServiceAdmin(proxy)) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) Delete(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| err = h.adminService.DeleteProxy(c.Request.Context(), proxyID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, gin.H{"message": "Proxy deleted successfully"}) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) BatchDelete(c *gin.Context) { |
| type BatchDeleteRequest struct { |
| IDs []int64 `json:"ids" binding:"required,min=1"` |
| } |
|
|
| var req BatchDeleteRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| result, err := h.adminService.BatchDeleteProxies(c.Request.Context(), req.IDs) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, result) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) Test(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| result, err := h.adminService.TestProxy(c.Request.Context(), proxyID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, result) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) CheckQuality(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| result, err := h.adminService.CheckProxyQuality(c.Request.Context(), proxyID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| response.Success(c, result) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) GetStats(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| |
| _ = proxyID |
| response.Success(c, gin.H{ |
| "total_accounts": 0, |
| "active_accounts": 0, |
| "total_requests": 0, |
| "success_rate": 100.0, |
| "average_latency": 0, |
| }) |
| } |
|
|
| |
| |
| func (h *ProxyHandler) GetProxyAccounts(c *gin.Context) { |
| proxyID, err := strconv.ParseInt(c.Param("id"), 10, 64) |
| if err != nil { |
| response.BadRequest(c, "Invalid proxy ID") |
| return |
| } |
|
|
| accounts, err := h.adminService.GetProxyAccounts(c.Request.Context(), proxyID) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| out := make([]dto.ProxyAccountSummary, 0, len(accounts)) |
| for i := range accounts { |
| out = append(out, *dto.ProxyAccountSummaryFromService(&accounts[i])) |
| } |
| response.Success(c, out) |
| } |
|
|
| |
| type BatchCreateProxyItem struct { |
| Protocol string `json:"protocol" binding:"required,oneof=http https socks5 socks5h"` |
| Host string `json:"host" binding:"required"` |
| Port int `json:"port" binding:"required,min=1,max=65535"` |
| Username string `json:"username"` |
| Password string `json:"password"` |
| } |
|
|
| |
| type BatchCreateRequest struct { |
| Proxies []BatchCreateProxyItem `json:"proxies" binding:"required,min=1"` |
| } |
|
|
| |
| |
| func (h *ProxyHandler) BatchCreate(c *gin.Context) { |
| var req BatchCreateRequest |
| if err := c.ShouldBindJSON(&req); err != nil { |
| response.BadRequest(c, "Invalid request: "+err.Error()) |
| return |
| } |
|
|
| created := 0 |
| skipped := 0 |
|
|
| for _, item := range req.Proxies { |
| |
| host := strings.TrimSpace(item.Host) |
| protocol := strings.TrimSpace(item.Protocol) |
| username := strings.TrimSpace(item.Username) |
| password := strings.TrimSpace(item.Password) |
|
|
| |
| exists, err := h.adminService.CheckProxyExists(c.Request.Context(), host, item.Port, username, password) |
| if err != nil { |
| response.ErrorFrom(c, err) |
| return |
| } |
|
|
| if exists { |
| skipped++ |
| continue |
| } |
|
|
| |
| _, err = h.adminService.CreateProxy(c.Request.Context(), &service.CreateProxyInput{ |
| Name: "default", |
| Protocol: protocol, |
| Host: host, |
| Port: item.Port, |
| Username: username, |
| Password: password, |
| }) |
| if err != nil { |
| |
| skipped++ |
| continue |
| } |
|
|
| created++ |
| } |
|
|
| response.Success(c, gin.H{ |
| "created": created, |
| "skipped": skipped, |
| }) |
| } |
|
|