spend_guard_handler.go 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. package admin
  2. import (
  3. "errors"
  4. "strconv"
  5. "github.com/Wei-Shaw/sub2api/internal/pkg/response"
  6. "github.com/Wei-Shaw/sub2api/internal/service"
  7. "github.com/gin-gonic/gin"
  8. )
  9. // SpendGuardHandler 烧钱防护:token 速率/错误率超阈自动冻结 key。
  10. type SpendGuardHandler struct {
  11. service *service.SpendGuardService
  12. }
  13. func NewSpendGuardHandler(svc *service.SpendGuardService) *SpendGuardHandler {
  14. return &SpendGuardHandler{service: svc}
  15. }
  16. func (h *SpendGuardHandler) requireService(c *gin.Context) bool {
  17. if h == nil || h.service == nil {
  18. response.ErrorFrom(c, errors.New("spend guard service unavailable"))
  19. return false
  20. }
  21. return true
  22. }
  23. // Offenders 窗口内各 key 用量与错误排行。
  24. // GET /api/v1/admin/spend-guard
  25. func (h *SpendGuardHandler) Offenders(c *gin.Context) {
  26. if !h.requireService(c) {
  27. return
  28. }
  29. items, err := h.service.Offenders(c.Request.Context(), 0)
  30. if err != nil {
  31. response.ErrorFrom(c, err)
  32. return
  33. }
  34. if items == nil {
  35. items = []service.SpendGuardOffender{}
  36. }
  37. response.Success(c, gin.H{"items": items, "count": len(items)})
  38. }
  39. // GetSettings 读取防护配置。
  40. // GET /api/v1/admin/spend-guard/settings
  41. func (h *SpendGuardHandler) GetSettings(c *gin.Context) {
  42. if !h.requireService(c) {
  43. return
  44. }
  45. response.Success(c, h.service.GetSettings(c.Request.Context()))
  46. }
  47. // UpdateSettings 更新防护配置。
  48. // PUT /api/v1/admin/spend-guard/settings
  49. func (h *SpendGuardHandler) UpdateSettings(c *gin.Context) {
  50. if !h.requireService(c) {
  51. return
  52. }
  53. var req service.SpendGuardSettings
  54. if err := c.ShouldBindJSON(&req); err != nil {
  55. response.BadRequest(c, "Invalid request: "+err.Error())
  56. return
  57. }
  58. out, err := h.service.UpdateSettings(c.Request.Context(), req)
  59. if err != nil {
  60. response.ErrorFrom(c, err)
  61. return
  62. }
  63. response.Success(c, out)
  64. }
  65. // Events 近期冻结/解冻事件。
  66. // GET /api/v1/admin/spend-guard/events
  67. func (h *SpendGuardHandler) Events(c *gin.Context) {
  68. if !h.requireService(c) {
  69. return
  70. }
  71. events := h.service.Events()
  72. if events == nil {
  73. events = []service.SpendGuardEvent{}
  74. }
  75. response.Success(c, gin.H{"items": events, "count": len(events)})
  76. }
  77. // Unfreeze 手动解冻 key。
  78. // POST /api/v1/admin/spend-guard/keys/:id/unfreeze
  79. func (h *SpendGuardHandler) Unfreeze(c *gin.Context) {
  80. if !h.requireService(c) {
  81. return
  82. }
  83. id, err := strconv.ParseInt(c.Param("id"), 10, 64)
  84. if err != nil || id <= 0 {
  85. response.BadRequest(c, "Invalid API key ID")
  86. return
  87. }
  88. if err := h.service.Unfreeze(c.Request.Context(), id); err != nil {
  89. response.ErrorFrom(c, err)
  90. return
  91. }
  92. response.Success(c, gin.H{"message": "API key unfrozen successfully"})
  93. }