package task import ( "code.gitea.io/gitea/models" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/redis/redis_key" "code.gitea.io/gitea/modules/redis/redis_lock" "code.gitea.io/gitea/modules/util" "code.gitea.io/gitea/services/reward" "code.gitea.io/gitea/services/reward/limiter" "fmt" "time" ) func Accomplish(userId int64, taskType string, sourceId string) { go accomplish(userId, taskType, sourceId) } func accomplish(userId int64, taskType string, sourceId string) error { defer func() { if err := recover(); err != nil { combinedErr := fmt.Errorf("%s\n%s", err, log.Stack(2)) log.Error("PANIC:%v", combinedErr) } }() //lock var taskLock = redis_lock.NewDistributeLock(redis_key.TaskAccomplishLock(sourceId, taskType)) isOk, err := taskLock.Lock(3 * time.Second) if err != nil { log.Error("get taskLock error. %v", err) return err } if !isOk { log.Info("duplicated task request,userId=%d taskType=%s sourceId=%s", userId, taskType, sourceId) return nil } defer taskLock.UnLock() //is handled before? isHandled, err := isHandled(taskType, sourceId) if err != nil { log.Error("Get isHandled error,%v", err) return err } if isHandled { log.Info("task has been handled,userId=%d taskType=%s sourceId=%s", userId, taskType, sourceId) return nil } //get task config config, err := GetTaskConfig(taskType) if err != nil { log.Error("GetTaskConfig error,%v", err) return err } if config == nil { log.Info("task config not exist,userId=%d taskType=%s sourceId=%s", userId, taskType, sourceId) return nil } //is limited? if isLimited(userId, config) { log.Info("task accomplish maximum times are reached,userId=%d taskType=%s sourceId=%s", userId, taskType, sourceId) return nil } //add log logId := util.UUID() _, err = models.InsertTaskAccomplishLog(&models.TaskAccomplishLog{ LogId: logId, ConfigId: config.ID, TaskCode: config.TaskCode, UserId: userId, SourceId: sourceId, }) if err != nil { return err } //reward reward.Send(models.RewardOperateContext{ SourceType: models.SourceTypeAccomplishTask, SourceId: logId, Reward: models.Reward{ Amount: config.AwardAmount, Type: config.AwardType, }, TargetUserId: userId, RequestId: logId, OperateType: models.OperateTypeIncrease, }) return nil } func isHandled(taskType string, sourceId string) (bool, error) { _, err := models.GetTaskAccomplishLogBySourceIdAndTaskCode(sourceId, taskType) if err != nil { if models.IsErrRecordNotExist(err) { return false, nil } return false, err } return true, nil } func isLimited(userId int64, config *models.TaskConfig) bool { if err := limiter.CheckLimit(config.TaskCode, models.LimitTypeTask, userId, 1); err != nil { return true } return false }