proxy_service.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package service
  2. import (
  3. "context"
  4. "fmt"
  5. "time"
  6. infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors"
  7. "github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
  8. )
  9. var (
  10. ErrProxyNotFound = infraerrors.NotFound("PROXY_NOT_FOUND", "proxy not found")
  11. ErrProxyInUse = infraerrors.Conflict("PROXY_IN_USE", "proxy is in use by accounts")
  12. )
  13. type ProxyRepository interface {
  14. Create(ctx context.Context, proxy *Proxy) error
  15. GetByID(ctx context.Context, id int64) (*Proxy, error)
  16. ListByIDs(ctx context.Context, ids []int64) ([]Proxy, error)
  17. Update(ctx context.Context, proxy *Proxy) error
  18. Delete(ctx context.Context, id int64) error
  19. List(ctx context.Context, params pagination.PaginationParams) ([]Proxy, *pagination.PaginationResult, error)
  20. ListWithFilters(ctx context.Context, params pagination.PaginationParams, protocol, status, search string) ([]Proxy, *pagination.PaginationResult, error)
  21. ListWithFiltersAndAccountCount(ctx context.Context, params pagination.PaginationParams, protocol, status, search string) ([]ProxyWithAccountCount, *pagination.PaginationResult, error)
  22. ListActive(ctx context.Context) ([]Proxy, error)
  23. ListActiveWithAccountCount(ctx context.Context) ([]ProxyWithAccountCount, error)
  24. ExistsByHostPortAuth(ctx context.Context, host string, port int, username, password string) (bool, error)
  25. CountAccountsByProxyID(ctx context.Context, proxyID int64) (int64, error)
  26. ListAccountSummariesByProxyID(ctx context.Context, proxyID int64) ([]ProxyAccountSummary, error)
  27. SweepExpiredProxies(ctx context.Context, now time.Time) (changed int64, err error)
  28. ListAllForFallback(ctx context.Context) ([]Proxy, error)
  29. CountExpired(ctx context.Context) (int64, error)
  30. CountExpiringSoon(ctx context.Context, now time.Time) (int64, error)
  31. }
  32. // CreateProxyRequest 创建代理请求
  33. type CreateProxyRequest struct {
  34. Name string `json:"name"`
  35. Protocol string `json:"protocol"`
  36. Host string `json:"host"`
  37. Port int `json:"port"`
  38. Username string `json:"username"`
  39. Password string `json:"password"`
  40. }
  41. // UpdateProxyRequest 更新代理请求
  42. type UpdateProxyRequest struct {
  43. Name *string `json:"name"`
  44. Protocol *string `json:"protocol"`
  45. Host *string `json:"host"`
  46. Port *int `json:"port"`
  47. Username *string `json:"username"`
  48. Password *string `json:"password"`
  49. Status *string `json:"status"`
  50. }
  51. // ProxyService 代理管理服务
  52. type ProxyService struct {
  53. proxyRepo ProxyRepository
  54. }
  55. // NewProxyService 创建代理服务实例
  56. func NewProxyService(proxyRepo ProxyRepository) *ProxyService {
  57. return &ProxyService{
  58. proxyRepo: proxyRepo,
  59. }
  60. }
  61. // Create 创建代理
  62. func (s *ProxyService) Create(ctx context.Context, req CreateProxyRequest) (*Proxy, error) {
  63. // 创建代理
  64. proxy := &Proxy{
  65. Name: req.Name,
  66. Protocol: req.Protocol,
  67. Host: req.Host,
  68. Port: req.Port,
  69. Username: req.Username,
  70. Password: req.Password,
  71. Status: StatusActive,
  72. }
  73. if err := s.proxyRepo.Create(ctx, proxy); err != nil {
  74. return nil, fmt.Errorf("create proxy: %w", err)
  75. }
  76. return proxy, nil
  77. }
  78. // GetByID 根据ID获取代理
  79. func (s *ProxyService) GetByID(ctx context.Context, id int64) (*Proxy, error) {
  80. proxy, err := s.proxyRepo.GetByID(ctx, id)
  81. if err != nil {
  82. return nil, fmt.Errorf("get proxy: %w", err)
  83. }
  84. return proxy, nil
  85. }
  86. // List 获取代理列表
  87. func (s *ProxyService) List(ctx context.Context, params pagination.PaginationParams) ([]Proxy, *pagination.PaginationResult, error) {
  88. proxies, pagination, err := s.proxyRepo.List(ctx, params)
  89. if err != nil {
  90. return nil, nil, fmt.Errorf("list proxies: %w", err)
  91. }
  92. return proxies, pagination, nil
  93. }
  94. // ListActive 获取活跃代理列表
  95. func (s *ProxyService) ListActive(ctx context.Context) ([]Proxy, error) {
  96. proxies, err := s.proxyRepo.ListActive(ctx)
  97. if err != nil {
  98. return nil, fmt.Errorf("list active proxies: %w", err)
  99. }
  100. return proxies, nil
  101. }
  102. // Update 更新代理
  103. func (s *ProxyService) Update(ctx context.Context, id int64, req UpdateProxyRequest) (*Proxy, error) {
  104. proxy, err := s.proxyRepo.GetByID(ctx, id)
  105. if err != nil {
  106. return nil, fmt.Errorf("get proxy: %w", err)
  107. }
  108. // 更新字段
  109. if req.Name != nil {
  110. proxy.Name = *req.Name
  111. }
  112. if req.Protocol != nil {
  113. proxy.Protocol = *req.Protocol
  114. }
  115. if req.Host != nil {
  116. proxy.Host = *req.Host
  117. }
  118. if req.Port != nil {
  119. proxy.Port = *req.Port
  120. }
  121. if req.Username != nil {
  122. proxy.Username = *req.Username
  123. }
  124. if req.Password != nil {
  125. proxy.Password = *req.Password
  126. }
  127. if req.Status != nil {
  128. proxy.Status = *req.Status
  129. }
  130. if err := s.proxyRepo.Update(ctx, proxy); err != nil {
  131. return nil, fmt.Errorf("update proxy: %w", err)
  132. }
  133. return proxy, nil
  134. }
  135. // Delete 删除代理
  136. func (s *ProxyService) Delete(ctx context.Context, id int64) error {
  137. // 检查代理是否存在
  138. _, err := s.proxyRepo.GetByID(ctx, id)
  139. if err != nil {
  140. return fmt.Errorf("get proxy: %w", err)
  141. }
  142. if err := s.proxyRepo.Delete(ctx, id); err != nil {
  143. return fmt.Errorf("delete proxy: %w", err)
  144. }
  145. return nil
  146. }
  147. // TestConnection 测试代理连接(需要实现具体测试逻辑)
  148. func (s *ProxyService) TestConnection(ctx context.Context, id int64) error {
  149. proxy, err := s.proxyRepo.GetByID(ctx, id)
  150. if err != nil {
  151. return fmt.Errorf("get proxy: %w", err)
  152. }
  153. // TODO: 实现代理连接测试逻辑
  154. // 可以尝试通过代理发送测试请求
  155. _ = proxy
  156. return nil
  157. }
  158. // GetURL 获取代理URL
  159. func (s *ProxyService) GetURL(ctx context.Context, id int64) (string, error) {
  160. proxy, err := s.proxyRepo.GetByID(ctx, id)
  161. if err != nil {
  162. return "", fmt.Errorf("get proxy: %w", err)
  163. }
  164. return proxy.URL(), nil
  165. }