package svc import ( "context" "errors" "fmt" ea "github.com/earn-alliance/earnalliance-go" "github.com/shopspring/decimal" "github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/rest" "nova_task/internal/config" "nova_task/internal/consts" "nova_task/internal/middleware" "nova_task/internal/model" "nova_task/internal/pkg/errs" "nova_task/internal/types" "time" ) type ServiceContext struct { Config config.Config TaskModel model.NhTaskModel taskAssetModel model.NhTaskAssetModel taskAssetRecordModel model.NhTaskAssetRecordModel TaskProgressModel model.NhTaskProgressModel TwitterModel model.NhTwitterModel PromoteBindModel model.NhPromoteBindModel TouristBindModel model.NhTouristBindModel CommunityModel model.NhTaskCommunityModel UserModel model.NhUserModel WalletModel model.NhWalletModel ConfigModel model.NhSystemConfigModel NftHolderModel model.NhNftHolderModel NftHolderChangeLogModel model.NhNftHolderChangeLogModel StakeNftModel model.NhTaskNftStakeModel OldStakeNftModel model.NhNftStakeModel StakeNftLogModel model.NhTaskNftStakeLogModel StakeRewardModel model.NhTaskNftStakeRewardModel GamePitModel model.NhGamePitModel StakePropertyModel model.NhNftStakePropertyModel EmailRewardModel model.NhEmailRewardModel AmbassadorModel model.NhTaskAmbassadorModel GameReportModel model.NhGameReportModel RoleModel model.NhRoleModel ApiKeyCheck rest.Middleware AdminSecretCheck rest.Middleware Game7ApiKeyCheck rest.Middleware KGeNApiKeyCheck rest.Middleware Earn *ea.Client DBConn sqlx.SqlConn Redis *redis.Redis } func NewServiceContext(c config.Config) *ServiceContext { dbConn := c.MySql.Conn() configModel := model.NewNhSystemConfigModel(dbConn, c.Cache) return &ServiceContext{ Config: c, TaskModel: model.NewNhTaskModel(dbConn), taskAssetModel: model.NewNhTaskAssetModel(dbConn), taskAssetRecordModel: model.NewNhTaskAssetRecordModel(dbConn), TaskProgressModel: model.NewNhTaskProgressModel(dbConn), TwitterModel: model.NewNhTwitterModel(dbConn), PromoteBindModel: model.NewNhPromoteBindModel(dbConn), CommunityModel: model.NewNhTaskCommunityModel(dbConn), UserModel: model.NewNhUserModel(dbConn), TouristBindModel: model.NewNhTouristBindModel(dbConn), WalletModel: model.NewNhWalletModel(dbConn), ConfigModel: configModel, NftHolderModel: model.NewNhNftHolderModel(dbConn), NftHolderChangeLogModel: model.NewNhNftHolderChangeLogModel(dbConn), StakeNftModel: model.NewNhTaskNftStakeModel(dbConn), OldStakeNftModel: model.NewNhNftStakeModel(dbConn), StakeRewardModel: model.NewNhTaskNftStakeRewardModel(dbConn), GamePitModel: model.NewNhGamePitModel(dbConn), StakePropertyModel: model.NewNhNftStakePropertyModel(dbConn), EmailRewardModel: model.NewNhEmailRewardModel(dbConn), AmbassadorModel: model.NewNhTaskAmbassadorModel(dbConn), GameReportModel: model.NewNhGameReportModel(dbConn), RoleModel: model.NewNhRoleModel(dbConn), ApiKeyCheck: middleware.NewApiKeyCheckMiddleware(configModel).Handle, AdminSecretCheck: middleware.NewAdminSecretCheckMiddleware(configModel).Handle, Game7ApiKeyCheck: middleware.NewGame7ApiKeyCheckMiddleware(configModel).Handle, KGeNApiKeyCheck: middleware.NewKGeNApiKeyCheckMiddleware(configModel).Handle, Earn: c.Earn.BuildEarnClient(), DBConn: dbConn, Redis: redis.MustNewRedis(c.Redis), } } func (s *ServiceContext) Close() { err := s.Earn.Flush() if err != nil { logx.Errorw("flush earn error", logx.Field("err", err)) } s.Earn.Close() } func (s *ServiceContext) IsAmbassador(ctx context.Context, uid uint, stage int8) bool { u, err := s.UserModel.FindOne(ctx, uid) if err != nil { if !errors.Is(err, model.ErrNotFound) { logx.Errorw("find user error", logx.Field("err", err), logx.Field("uid", uid), logx.Field("stage", stage)) } return false } _, err = s.AmbassadorModel.FindOneByEmailStage(ctx, u.Email, stage) if err != nil { if !errors.Is(err, model.ErrNotFound) { logx.Errorw("find ambassador error", logx.Field("err", err), logx.Field("uid", uid), logx.Field("stage", stage)) } return false } return true } func (s *ServiceContext) HasBindTwitter(ctx context.Context, uid uint) bool { tw, err := s.TwitterModel.FindOneByUid(ctx, uid) if err != nil { if !errors.Is(err, model.ErrNotFound) { logx.Errorw("find twitter error", logx.Field("err", err), logx.Field("uid", uid)) } return false } return tw.TwitterId != "" } func (s *ServiceContext) GetUidByEmail(ctx context.Context, email string) (uint, *types.CarvResult) { u, err := s.UserModel.FindOneByEmail(ctx, email) if err != nil { if !errors.Is(err, model.ErrNotFound) { return 0, &types.CarvResult{ Error: &types.Error{ Code: int(errs.ErrDatabaseOperate), Message: "system error", }, } } return 0, &types.CarvResult{ Error: &types.Error{ Code: int(errs.ErrUserNotFound), Message: "email not exist", }, } } return u.Id, nil } func (s *ServiceContext) AddUserAssetWithSession(ctx context.Context, session sqlx.Session, uid uint, asset consts.AssetType, amount decimal.Decimal, remark string, eventId uint64, provideUid uint, referralReward bool) error { var assetModel model.NhTaskAssetModel var recordModel model.NhTaskAssetRecordModel if session != nil { assetModel = s.taskAssetModel.WithSession(session) recordModel = s.taskAssetRecordModel.WithSession(session) } else { assetModel = s.taskAssetModel recordModel = s.taskAssetRecordModel } var err error switch asset { case consts.AssetType_Points: err = assetModel.AddPoint(ctx, uid, amount) case consts.AssetType_Castile: err = assetModel.AddCastile(ctx, uid, amount) case consts.AssetType_Elite_Points: err = assetModel.AddElitePoints(ctx, uid, amount) case consts.AssetType_Keys: err = assetModel.AddKeys(ctx, uid, int(amount.IntPart())) default: return errors.New("unknown asset type") } if err != nil { return err } _, err = recordModel.Insert(ctx, &model.NhTaskAssetRecord{ Uid: int(uid), EventId: eventId, AssetField: string(asset), Count: amount.InexactFloat64(), Remark: remark, ProvideUid: provideUid, CreateTime: int(time.Now().Unix()), }) if err != nil { return err } if !referralReward { return nil } // 返利给上级 pb, err := s.PromoteBindModel.FindOneByInvitedUid(ctx, uid) if err != nil { if !errors.Is(err, model.ErrNotFound) { logx.Errorw("find promote bind error", logx.Field("err", err), logx.Field("uid", uid)) } return nil } if pb.ShareUid == 0 { return nil } var rate = 5 if s.NftHolderModel.HoldNft(ctx, pb.ShareUid) { rate = 15 } else if s.AmbassadorModel.IsAmbassador(ctx, pb.ShareUid) { rate = 10 } rated := decimal.NewFromFloat(float64(rate) / 100) rewardAmount := amount.Mul(rated) return s.AddUserAssetWithSession(ctx, session, pb.ShareUid, asset, rewardAmount, fmt.Sprintf("分享返利,比例%s", rated.String()), 7, uid, false) } func (s *ServiceContext) AddUserAsset(ctx context.Context, uid uint, asset consts.AssetType, amount decimal.Decimal, remark string, eventId uint64, provideUid uint, referralReward bool) error { return s.AddUserAssetWithSession(ctx, nil, uid, asset, amount, remark, eventId, provideUid, referralReward) }