You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

operator.go 3.5 kB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. package reward
  2. import (
  3. "code.gitea.io/gitea/models"
  4. "code.gitea.io/gitea/modules/log"
  5. "code.gitea.io/gitea/modules/redis/redis_key"
  6. "code.gitea.io/gitea/modules/redis/redis_lock"
  7. "code.gitea.io/gitea/modules/util"
  8. "code.gitea.io/gitea/services/reward/point"
  9. "errors"
  10. "fmt"
  11. "time"
  12. )
  13. var RewardOperatorMap = map[string]RewardOperator{
  14. fmt.Sprint(models.RewardTypePoint): new(point.PointOperator),
  15. }
  16. type RewardOperator interface {
  17. IsLimited(ctx models.RewardOperateContext) bool
  18. Operate(ctx models.RewardOperateContext) error
  19. }
  20. func Send(ctx models.RewardOperateContext) error {
  21. defer func() {
  22. if err := recover(); err != nil {
  23. combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2))
  24. log.Error("PANIC:%v", combinedErr)
  25. }
  26. }()
  27. //add lock
  28. var rewardLock = redis_lock.NewDistributeLock(redis_key.RewardSendLock(ctx.RequestId, ctx.SourceType))
  29. isOk, err := rewardLock.Lock(3 * time.Second)
  30. if err != nil {
  31. return err
  32. }
  33. if !isOk {
  34. log.Info("duplicated reward request,targetUserId=%d requestId=%s", ctx.TargetUserId, ctx.RequestId)
  35. return nil
  36. }
  37. defer rewardLock.UnLock()
  38. //is handled before?
  39. isHandled, err := isHandled(ctx.SourceType, ctx.RequestId)
  40. if err != nil {
  41. log.Error("reward is handled error,%v", err)
  42. return err
  43. }
  44. if isHandled {
  45. log.Info("reward has been handled,ctx=%+v", ctx)
  46. return nil
  47. }
  48. //get operator
  49. operator := GetOperator(ctx.Reward.Type)
  50. if operator == nil {
  51. return errors.New("operator of reward type is not exist")
  52. }
  53. //is limited?
  54. if isLimited := operator.IsLimited(ctx); isLimited {
  55. return nil
  56. }
  57. //new reward operate record
  58. recordId, err := initAwardOperateRecord(ctx)
  59. if err != nil {
  60. return err
  61. }
  62. ctx.SourceId = recordId
  63. //operate
  64. if err := operator.Operate(ctx); err != nil {
  65. updateAwardOperateRecordStatus(ctx.SourceType, ctx.RequestId, models.OperateStatusOperating, models.OperateStatusFailed)
  66. return err
  67. }
  68. //if not a cycle operate,update status to success
  69. if ctx.CycleIntervalSeconds == 0 {
  70. updateAwardOperateRecordStatus(ctx.SourceType, ctx.RequestId, models.OperateStatusOperating, models.OperateStatusSucceeded)
  71. }
  72. return nil
  73. }
  74. func GetOperator(rewardType string) RewardOperator {
  75. return RewardOperatorMap[rewardType]
  76. }
  77. func isHandled(sourceType string, requestId string) (bool, error) {
  78. _, err := models.GetPointOperateRecordBySourceTypeAndRequestId(sourceType, requestId)
  79. if err != nil {
  80. if models.IsErrRecordNotExist(err) {
  81. return false, nil
  82. }
  83. return false, err
  84. }
  85. return true, nil
  86. }
  87. func initAwardOperateRecord(ctx models.RewardOperateContext) (string, error) {
  88. record := &models.RewardOperateRecord{
  89. RecordId: util.UUID(),
  90. UserId: ctx.TargetUserId,
  91. Amount: ctx.Reward.Amount,
  92. RewardType: ctx.Reward.Type,
  93. SourceType: ctx.SourceType,
  94. SourceId: ctx.SourceId,
  95. RequestId: ctx.RequestId,
  96. OperateType: ctx.OperateType,
  97. CycleIntervalSeconds: ctx.CycleIntervalSeconds,
  98. Status: models.OperateStatusOperating,
  99. Remark: ctx.Remark,
  100. }
  101. _, err := models.InsertAwardOperateRecord(record)
  102. if err != nil {
  103. return "", err
  104. }
  105. return record.RecordId, nil
  106. }
  107. func updateAwardOperateRecordStatus(sourceType, requestId, oldStatus, newStatus string) error {
  108. _, err := models.UpdateAwardOperateRecordStatus(sourceType, requestId, oldStatus, newStatus)
  109. if err != nil {
  110. return err
  111. }
  112. return nil
  113. }