ratelimit.go 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. package dao
  2. import (
  3. "context"
  4. "crypto/md5"
  5. "fmt"
  6. "strconv"
  7. "time"
  8. "go-common/library/cache/redis"
  9. "go-common/library/ecode"
  10. "go-common/library/log"
  11. )
  12. // LimitCheckInfo 频率限制检查参数
  13. type LimitCheckInfo struct {
  14. UID int64
  15. RoomID int64
  16. Msg string
  17. MsgType int64
  18. Dao *Dao
  19. Conf *LimitConf
  20. }
  21. const (
  22. _MaxGiftMsgNum = "r:m:stormmsgcount:"
  23. _MAXMsgNum = "r:m:rmx:"
  24. )
  25. // LimitPerSec 每秒发言限制
  26. func (l *LimitCheckInfo) LimitPerSec(ctx context.Context) error {
  27. key := fmt.Sprintf("%d.%d", l.UID, time.Now().Unix())
  28. var conn = l.Dao.redis.Get(ctx)
  29. defer conn.Close()
  30. ret, err := conn.Do("SET", key, 1, "EX", 1, "NX")
  31. if err != nil {
  32. log.Error("limitPerSec:conn.Do(SET EX NX) %s %d %v", key, 1, err)
  33. return nil
  34. }
  35. if ret != nil {
  36. return nil
  37. }
  38. return ecode.Error(0, "msg in 1s")
  39. }
  40. //LimitSameMsg 同一个用户同一房间5s 只能发送一条相同弹幕
  41. func (l *LimitCheckInfo) LimitSameMsg(ctx context.Context) error {
  42. key := fmt.Sprintf("%d.%s", l.RoomID, md5.Sum([]byte(strconv.FormatInt(l.UID, 10)+l.Msg)))
  43. var conn = l.Dao.redis.Get(ctx)
  44. defer conn.Close()
  45. ret, err := conn.Do("SET", key, 1, "EX", 5, "NX")
  46. if err != nil {
  47. log.Error("DM LimitSameMsg conn.Do(SET, %s, 1, EX, 5, NX) error(%v)", key, err)
  48. return nil
  49. }
  50. if ret != nil {
  51. return nil
  52. }
  53. return ecode.Error(0, "msg repeat")
  54. }
  55. //LimitRoomPerSecond 单房间每秒只能发送制定条数弹幕
  56. func (l *LimitCheckInfo) LimitRoomPerSecond(ctx context.Context) error {
  57. maxNum := l.Conf.DmNum
  58. percent := l.Conf.DMPercent
  59. danNum := maxNum * percent / 100.0
  60. giftNum := maxNum - danNum
  61. msgKey := fmt.Sprintf("%s.%d.%d", _MAXMsgNum, l.RoomID, time.Now().Unix())
  62. giftKey := fmt.Sprintf("%s.%d.%d", _MaxGiftMsgNum, l.RoomID, time.Now().Unix())
  63. var conn = l.Dao.redis.Get(ctx)
  64. defer conn.Close()
  65. if l.MsgType != 0 {
  66. //礼物弹幕
  67. if count, err := redis.Int64(conn.Do("INCRBY", giftKey, 1)); err != nil {
  68. log.Error("DMRateLimit: LimitRoomPerSecond INCRBY err: %v", err)
  69. } else {
  70. if count > giftNum {
  71. return ecode.Error(0, "max limit")
  72. }
  73. }
  74. if _, err := conn.Do("EXPIRE", giftKey, 2); err != nil {
  75. log.Error("DMRateLimit: LimitRoomPerSecond EXPIRE err: %v", err)
  76. }
  77. return nil
  78. }
  79. //普通弹幕
  80. var max = maxNum
  81. if exit, err := redis.Bool(conn.Do("EXISTS", giftKey)); err != nil {
  82. log.Error("DMRateLimit: LimitRoomPerSecond EXISTS gift err: %v", err)
  83. } else {
  84. if exit {
  85. max = danNum
  86. } else {
  87. max = maxNum
  88. }
  89. }
  90. if count, err := redis.Int64(conn.Do("INCRBY", msgKey, 1)); err != nil {
  91. log.Error("DMRateLimit: LimitRoomPerSecond INCR err: %v", err)
  92. } else {
  93. if count > max {
  94. return ecode.Error(0, "max limit")
  95. }
  96. }
  97. if _, err := conn.Do("EXPIRE", msgKey, 2); err != nil {
  98. log.Error("DMRateLimit: LimitRoomPerSecond EXPIRE err: %v", err)
  99. }
  100. return nil
  101. }