component.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package rate
  2. import (
  3. "f1-game/internal/code"
  4. "f1-game/internal/data"
  5. "time"
  6. cherryFacade "github.com/cherry-game/cherry/facade"
  7. clog "github.com/cherry-game/cherry/logger"
  8. cherryGin "github.com/cherry-game/components/gin"
  9. )
  10. var (
  11. _buckets = NewBuckets() // bucket list
  12. _rateRow = &data.RateLimiterRow{} // rate config
  13. )
  14. type (
  15. //Component 限速组件
  16. component struct {
  17. cherryFacade.Component
  18. }
  19. )
  20. func New() *component {
  21. return &component{}
  22. }
  23. func (c *component) Name() string {
  24. return "rate_limiter_component"
  25. }
  26. func (c *component) Init() {
  27. rateID := c.App().Settings().GetString("rate_id")
  28. if rateID == "" {
  29. return
  30. }
  31. _rateRow, _ = data.RateLimiter.GetByRateID(rateID)
  32. if _rateRow == nil {
  33. clog.Errorf("Load rateLimiter config fail. rateID = %s", rateID)
  34. return
  35. }
  36. if _rateRow.Enable {
  37. go c.runCleanRateTimer()
  38. }
  39. }
  40. func (c *component) runCleanRateTimer() {
  41. clog.Infof("Clean rate timer is running. [rateID = %s]", _rateRow.RateID)
  42. cleanTicker := time.NewTicker(time.Duration(_rateRow.CleanTickerInterval) * time.Second)
  43. for {
  44. <-cleanTicker.C
  45. _buckets.Clean(_rateRow.CleanBeforeMinute)
  46. }
  47. }
  48. func GetBucket(name string) (*Bucket, bool) {
  49. if !_rateRow.Enable {
  50. return nil, false
  51. }
  52. bucket, found := _buckets.Get(name)
  53. if !found {
  54. bucket, found = _buckets.Add(name, time.Duration(_rateRow.Interval)*time.Second, _rateRow.Capacity, _rateRow.Quantum)
  55. }
  56. return bucket, found
  57. }
  58. func RemoveBucket(name string) {
  59. _buckets.Remove(name)
  60. }
  61. func Check(name string) int32 {
  62. if name == "" || !_rateRow.Enable {
  63. return code.OK
  64. }
  65. if bucket, found := GetBucket(name); found {
  66. if bucket.TakeAvailable(1) < 1 {
  67. clog.Warnf("rate limiter warn! [name = %s]", name)
  68. return _rateRow.ErrorCode
  69. }
  70. }
  71. return code.OK
  72. }
  73. func GinRateWithIP() cherryGin.GinHandlerFunc {
  74. return func(ctx *cherryGin.Context) {
  75. errCode := Check(ctx.RemoteIP())
  76. if code.IsFail(errCode) {
  77. rspData := code.NewDataResult(_rateRow.ErrorCode)
  78. ctx.JSON200(rspData)
  79. ctx.Abort()
  80. return
  81. }
  82. ctx.Next()
  83. }
  84. }