From d089f4f2821f41a1bd3d84c85e65e16474700e03 Mon Sep 17 00:00:00 2001 From: ZuoZuo <68836346+Mrz-sakura@users.noreply.github.com> Date: Thu, 28 May 2026 00:36:39 +0800 Subject: [PATCH 1/3] lucky_gift_v2: update lucky gift activity --- .gitignore | 2 + api/proto/activity/v1/activity.pb.go | 778 +++++++++++++----- api/proto/activity/v1/activity.proto | 40 +- .../internal/modules/luckygift/handler.go | 229 +++--- .../modules/luckygift/handler_test.go | 107 +++ .../mysql/initdb/001_activity_service.sql | 34 + .../internal/domain/luckygift/lucky_gift.go | 44 + .../internal/service/luckygift/config.go | 190 ++++- .../internal/service/luckygift/config_test.go | 36 + .../internal/service/luckygift/service.go | 37 +- .../service/luckygift/service_test.go | 20 +- .../storage/mysql/lucky_gift_repository.go | 150 +--- .../lucky_gift_rule_config_repository.go | 215 +++++ .../internal/storage/mysql/repository.go | 46 ++ .../transport/grpc/lucky_gift_server.go | 160 ++-- 15 files changed, 1444 insertions(+), 644 deletions(-) create mode 100644 server/admin/internal/modules/luckygift/handler_test.go create mode 100644 services/activity-service/internal/storage/mysql/lucky_gift_rule_config_repository.go diff --git a/.gitignore b/.gitignore index 32ae44db..35b9757e 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,5 @@ node_modules/ # Docker and database runtime data. mysql-data/ redis-data/ + +.waylog/ \ No newline at end of file diff --git a/api/proto/activity/v1/activity.pb.go b/api/proto/activity/v1/activity.pb.go index e337adad..2e9cf6c2 100644 --- a/api/proto/activity/v1/activity.pb.go +++ b/api/proto/activity/v1/activity.pb.go @@ -10532,6 +10532,298 @@ func (x *LuckyGiftConfig) GetMultiplierPpms() []int64 { return nil } +type LuckyGiftRuleTier struct { + state protoimpl.MessageState `protogen:"open.v1"` + Stage string `protobuf:"bytes,1,opt,name=stage,proto3" json:"stage,omitempty"` + TierId string `protobuf:"bytes,2,opt,name=tier_id,json=tierId,proto3" json:"tier_id,omitempty"` + MultiplierPpm int64 `protobuf:"varint,3,opt,name=multiplier_ppm,json=multiplierPpm,proto3" json:"multiplier_ppm,omitempty"` + BaseWeightPpm int64 `protobuf:"varint,4,opt,name=base_weight_ppm,json=baseWeightPpm,proto3" json:"base_weight_ppm,omitempty"` + RewardSource string `protobuf:"bytes,5,opt,name=reward_source,json=rewardSource,proto3" json:"reward_source,omitempty"` + HighWaterOnly bool `protobuf:"varint,6,opt,name=high_water_only,json=highWaterOnly,proto3" json:"high_water_only,omitempty"` + BroadcastLevel string `protobuf:"bytes,7,opt,name=broadcast_level,json=broadcastLevel,proto3" json:"broadcast_level,omitempty"` + Enabled bool `protobuf:"varint,8,opt,name=enabled,proto3" json:"enabled,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LuckyGiftRuleTier) Reset() { + *x = LuckyGiftRuleTier{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[128] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LuckyGiftRuleTier) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LuckyGiftRuleTier) ProtoMessage() {} + +func (x *LuckyGiftRuleTier) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[128] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LuckyGiftRuleTier.ProtoReflect.Descriptor instead. +func (*LuckyGiftRuleTier) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{128} +} + +func (x *LuckyGiftRuleTier) GetStage() string { + if x != nil { + return x.Stage + } + return "" +} + +func (x *LuckyGiftRuleTier) GetTierId() string { + if x != nil { + return x.TierId + } + return "" +} + +func (x *LuckyGiftRuleTier) GetMultiplierPpm() int64 { + if x != nil { + return x.MultiplierPpm + } + return 0 +} + +func (x *LuckyGiftRuleTier) GetBaseWeightPpm() int64 { + if x != nil { + return x.BaseWeightPpm + } + return 0 +} + +func (x *LuckyGiftRuleTier) GetRewardSource() string { + if x != nil { + return x.RewardSource + } + return "" +} + +func (x *LuckyGiftRuleTier) GetHighWaterOnly() bool { + if x != nil { + return x.HighWaterOnly + } + return false +} + +func (x *LuckyGiftRuleTier) GetBroadcastLevel() string { + if x != nil { + return x.BroadcastLevel + } + return "" +} + +func (x *LuckyGiftRuleTier) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +type LuckyGiftRuleStage struct { + state protoimpl.MessageState `protogen:"open.v1"` + Stage string `protobuf:"bytes,1,opt,name=stage,proto3" json:"stage,omitempty"` + Tiers []*LuckyGiftRuleTier `protobuf:"bytes,2,rep,name=tiers,proto3" json:"tiers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LuckyGiftRuleStage) Reset() { + *x = LuckyGiftRuleStage{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[129] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LuckyGiftRuleStage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LuckyGiftRuleStage) ProtoMessage() {} + +func (x *LuckyGiftRuleStage) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[129] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LuckyGiftRuleStage.ProtoReflect.Descriptor instead. +func (*LuckyGiftRuleStage) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{129} +} + +func (x *LuckyGiftRuleStage) GetStage() string { + if x != nil { + return x.Stage + } + return "" +} + +func (x *LuckyGiftRuleStage) GetTiers() []*LuckyGiftRuleTier { + if x != nil { + return x.Tiers + } + return nil +} + +type LuckyGiftRuleConfig struct { + state protoimpl.MessageState `protogen:"open.v1"` + AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"` + PoolId string `protobuf:"bytes,2,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"` + RuleVersion int64 `protobuf:"varint,3,opt,name=rule_version,json=ruleVersion,proto3" json:"rule_version,omitempty"` + Enabled bool `protobuf:"varint,4,opt,name=enabled,proto3" json:"enabled,omitempty"` + TargetRtpPpm int64 `protobuf:"varint,5,opt,name=target_rtp_ppm,json=targetRtpPpm,proto3" json:"target_rtp_ppm,omitempty"` + PoolRatePpm int64 `protobuf:"varint,6,opt,name=pool_rate_ppm,json=poolRatePpm,proto3" json:"pool_rate_ppm,omitempty"` + SettlementWindowWager int64 `protobuf:"varint,7,opt,name=settlement_window_wager,json=settlementWindowWager,proto3" json:"settlement_window_wager,omitempty"` + ControlBandPpm int64 `protobuf:"varint,8,opt,name=control_band_ppm,json=controlBandPpm,proto3" json:"control_band_ppm,omitempty"` + GiftPriceReference int64 `protobuf:"varint,9,opt,name=gift_price_reference,json=giftPriceReference,proto3" json:"gift_price_reference,omitempty"` + EffectiveFromMs int64 `protobuf:"varint,10,opt,name=effective_from_ms,json=effectiveFromMs,proto3" json:"effective_from_ms,omitempty"` + CreatedByAdminId int64 `protobuf:"varint,11,opt,name=created_by_admin_id,json=createdByAdminId,proto3" json:"created_by_admin_id,omitempty"` + CreatedAtMs int64 `protobuf:"varint,12,opt,name=created_at_ms,json=createdAtMs,proto3" json:"created_at_ms,omitempty"` + Stages []*LuckyGiftRuleStage `protobuf:"bytes,13,rep,name=stages,proto3" json:"stages,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache +} + +func (x *LuckyGiftRuleConfig) Reset() { + *x = LuckyGiftRuleConfig{} + mi := &file_proto_activity_v1_activity_proto_msgTypes[130] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) +} + +func (x *LuckyGiftRuleConfig) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LuckyGiftRuleConfig) ProtoMessage() {} + +func (x *LuckyGiftRuleConfig) ProtoReflect() protoreflect.Message { + mi := &file_proto_activity_v1_activity_proto_msgTypes[130] + if x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LuckyGiftRuleConfig.ProtoReflect.Descriptor instead. +func (*LuckyGiftRuleConfig) Descriptor() ([]byte, []int) { + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{130} +} + +func (x *LuckyGiftRuleConfig) GetAppCode() string { + if x != nil { + return x.AppCode + } + return "" +} + +func (x *LuckyGiftRuleConfig) GetPoolId() string { + if x != nil { + return x.PoolId + } + return "" +} + +func (x *LuckyGiftRuleConfig) GetRuleVersion() int64 { + if x != nil { + return x.RuleVersion + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetEnabled() bool { + if x != nil { + return x.Enabled + } + return false +} + +func (x *LuckyGiftRuleConfig) GetTargetRtpPpm() int64 { + if x != nil { + return x.TargetRtpPpm + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetPoolRatePpm() int64 { + if x != nil { + return x.PoolRatePpm + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetSettlementWindowWager() int64 { + if x != nil { + return x.SettlementWindowWager + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetControlBandPpm() int64 { + if x != nil { + return x.ControlBandPpm + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetGiftPriceReference() int64 { + if x != nil { + return x.GiftPriceReference + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetEffectiveFromMs() int64 { + if x != nil { + return x.EffectiveFromMs + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetCreatedByAdminId() int64 { + if x != nil { + return x.CreatedByAdminId + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetCreatedAtMs() int64 { + if x != nil { + return x.CreatedAtMs + } + return 0 +} + +func (x *LuckyGiftRuleConfig) GetStages() []*LuckyGiftRuleStage { + if x != nil { + return x.Stages + } + return nil +} + type CheckLuckyGiftRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` @@ -10545,7 +10837,7 @@ type CheckLuckyGiftRequest struct { func (x *CheckLuckyGiftRequest) Reset() { *x = CheckLuckyGiftRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[128] + mi := &file_proto_activity_v1_activity_proto_msgTypes[131] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10557,7 +10849,7 @@ func (x *CheckLuckyGiftRequest) String() string { func (*CheckLuckyGiftRequest) ProtoMessage() {} func (x *CheckLuckyGiftRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[128] + mi := &file_proto_activity_v1_activity_proto_msgTypes[131] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10570,7 +10862,7 @@ func (x *CheckLuckyGiftRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckLuckyGiftRequest.ProtoReflect.Descriptor instead. func (*CheckLuckyGiftRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{128} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{131} } func (x *CheckLuckyGiftRequest) GetMeta() *RequestMeta { @@ -10624,7 +10916,7 @@ type CheckLuckyGiftResponse struct { func (x *CheckLuckyGiftResponse) Reset() { *x = CheckLuckyGiftResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[129] + mi := &file_proto_activity_v1_activity_proto_msgTypes[132] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10636,7 +10928,7 @@ func (x *CheckLuckyGiftResponse) String() string { func (*CheckLuckyGiftResponse) ProtoMessage() {} func (x *CheckLuckyGiftResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[129] + mi := &file_proto_activity_v1_activity_proto_msgTypes[132] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10649,7 +10941,7 @@ func (x *CheckLuckyGiftResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use CheckLuckyGiftResponse.ProtoReflect.Descriptor instead. func (*CheckLuckyGiftResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{129} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{132} } func (x *CheckLuckyGiftResponse) GetEnabled() bool { @@ -10737,7 +11029,7 @@ type LuckyGiftDrawResult struct { func (x *LuckyGiftDrawResult) Reset() { *x = LuckyGiftDrawResult{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[130] + mi := &file_proto_activity_v1_activity_proto_msgTypes[133] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10749,7 +11041,7 @@ func (x *LuckyGiftDrawResult) String() string { func (*LuckyGiftDrawResult) ProtoMessage() {} func (x *LuckyGiftDrawResult) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[130] + mi := &file_proto_activity_v1_activity_proto_msgTypes[133] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10762,7 +11054,7 @@ func (x *LuckyGiftDrawResult) ProtoReflect() protoreflect.Message { // Deprecated: Use LuckyGiftDrawResult.ProtoReflect.Descriptor instead. func (*LuckyGiftDrawResult) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{130} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{133} } func (x *LuckyGiftDrawResult) GetDrawId() string { @@ -10921,7 +11213,7 @@ type ExecuteLuckyGiftDrawRequest struct { func (x *ExecuteLuckyGiftDrawRequest) Reset() { *x = ExecuteLuckyGiftDrawRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[131] + mi := &file_proto_activity_v1_activity_proto_msgTypes[134] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10933,7 +11225,7 @@ func (x *ExecuteLuckyGiftDrawRequest) String() string { func (*ExecuteLuckyGiftDrawRequest) ProtoMessage() {} func (x *ExecuteLuckyGiftDrawRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[131] + mi := &file_proto_activity_v1_activity_proto_msgTypes[134] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10946,7 +11238,7 @@ func (x *ExecuteLuckyGiftDrawRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecuteLuckyGiftDrawRequest.ProtoReflect.Descriptor instead. func (*ExecuteLuckyGiftDrawRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{131} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{134} } func (x *ExecuteLuckyGiftDrawRequest) GetLuckyGift() *LuckyGiftMeta { @@ -10965,7 +11257,7 @@ type ExecuteLuckyGiftDrawResponse struct { func (x *ExecuteLuckyGiftDrawResponse) Reset() { *x = ExecuteLuckyGiftDrawResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[132] + mi := &file_proto_activity_v1_activity_proto_msgTypes[135] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -10977,7 +11269,7 @@ func (x *ExecuteLuckyGiftDrawResponse) String() string { func (*ExecuteLuckyGiftDrawResponse) ProtoMessage() {} func (x *ExecuteLuckyGiftDrawResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[132] + mi := &file_proto_activity_v1_activity_proto_msgTypes[135] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -10990,7 +11282,7 @@ func (x *ExecuteLuckyGiftDrawResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecuteLuckyGiftDrawResponse.ProtoReflect.Descriptor instead. func (*ExecuteLuckyGiftDrawResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{132} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{135} } func (x *ExecuteLuckyGiftDrawResponse) GetResult() *LuckyGiftDrawResult { @@ -11011,7 +11303,7 @@ type GetLuckyGiftConfigRequest struct { func (x *GetLuckyGiftConfigRequest) Reset() { *x = GetLuckyGiftConfigRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[133] + mi := &file_proto_activity_v1_activity_proto_msgTypes[136] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11023,7 +11315,7 @@ func (x *GetLuckyGiftConfigRequest) String() string { func (*GetLuckyGiftConfigRequest) ProtoMessage() {} func (x *GetLuckyGiftConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[133] + mi := &file_proto_activity_v1_activity_proto_msgTypes[136] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11036,7 +11328,7 @@ func (x *GetLuckyGiftConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLuckyGiftConfigRequest.ProtoReflect.Descriptor instead. func (*GetLuckyGiftConfigRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{133} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{136} } func (x *GetLuckyGiftConfigRequest) GetMeta() *RequestMeta { @@ -11062,14 +11354,14 @@ func (x *GetLuckyGiftConfigRequest) GetPoolId() string { type GetLuckyGiftConfigResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Config *LuckyGiftConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + Config *LuckyGiftRuleConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *GetLuckyGiftConfigResponse) Reset() { *x = GetLuckyGiftConfigResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[134] + mi := &file_proto_activity_v1_activity_proto_msgTypes[137] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11081,7 +11373,7 @@ func (x *GetLuckyGiftConfigResponse) String() string { func (*GetLuckyGiftConfigResponse) ProtoMessage() {} func (x *GetLuckyGiftConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[134] + mi := &file_proto_activity_v1_activity_proto_msgTypes[137] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11094,10 +11386,10 @@ func (x *GetLuckyGiftConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLuckyGiftConfigResponse.ProtoReflect.Descriptor instead. func (*GetLuckyGiftConfigResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{134} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{137} } -func (x *GetLuckyGiftConfigResponse) GetConfig() *LuckyGiftConfig { +func (x *GetLuckyGiftConfigResponse) GetConfig() *LuckyGiftRuleConfig { if x != nil { return x.Config } @@ -11107,7 +11399,7 @@ func (x *GetLuckyGiftConfigResponse) GetConfig() *LuckyGiftConfig { type UpsertLuckyGiftConfigRequest struct { state protoimpl.MessageState `protogen:"open.v1"` Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"` - Config *LuckyGiftConfig `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` + Config *LuckyGiftRuleConfig `protobuf:"bytes,2,opt,name=config,proto3" json:"config,omitempty"` OperatorAdminId int64 `protobuf:"varint,3,opt,name=operator_admin_id,json=operatorAdminId,proto3" json:"operator_admin_id,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache @@ -11115,7 +11407,7 @@ type UpsertLuckyGiftConfigRequest struct { func (x *UpsertLuckyGiftConfigRequest) Reset() { *x = UpsertLuckyGiftConfigRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[135] + mi := &file_proto_activity_v1_activity_proto_msgTypes[138] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11127,7 +11419,7 @@ func (x *UpsertLuckyGiftConfigRequest) String() string { func (*UpsertLuckyGiftConfigRequest) ProtoMessage() {} func (x *UpsertLuckyGiftConfigRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[135] + mi := &file_proto_activity_v1_activity_proto_msgTypes[138] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11140,7 +11432,7 @@ func (x *UpsertLuckyGiftConfigRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpsertLuckyGiftConfigRequest.ProtoReflect.Descriptor instead. func (*UpsertLuckyGiftConfigRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{135} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{138} } func (x *UpsertLuckyGiftConfigRequest) GetMeta() *RequestMeta { @@ -11150,7 +11442,7 @@ func (x *UpsertLuckyGiftConfigRequest) GetMeta() *RequestMeta { return nil } -func (x *UpsertLuckyGiftConfigRequest) GetConfig() *LuckyGiftConfig { +func (x *UpsertLuckyGiftConfigRequest) GetConfig() *LuckyGiftRuleConfig { if x != nil { return x.Config } @@ -11166,14 +11458,14 @@ func (x *UpsertLuckyGiftConfigRequest) GetOperatorAdminId() int64 { type UpsertLuckyGiftConfigResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Config *LuckyGiftConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` + Config *LuckyGiftRuleConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *UpsertLuckyGiftConfigResponse) Reset() { *x = UpsertLuckyGiftConfigResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[136] + mi := &file_proto_activity_v1_activity_proto_msgTypes[139] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11185,7 +11477,7 @@ func (x *UpsertLuckyGiftConfigResponse) String() string { func (*UpsertLuckyGiftConfigResponse) ProtoMessage() {} func (x *UpsertLuckyGiftConfigResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[136] + mi := &file_proto_activity_v1_activity_proto_msgTypes[139] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11198,10 +11490,10 @@ func (x *UpsertLuckyGiftConfigResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use UpsertLuckyGiftConfigResponse.ProtoReflect.Descriptor instead. func (*UpsertLuckyGiftConfigResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{136} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{139} } -func (x *UpsertLuckyGiftConfigResponse) GetConfig() *LuckyGiftConfig { +func (x *UpsertLuckyGiftConfigResponse) GetConfig() *LuckyGiftRuleConfig { if x != nil { return x.Config } @@ -11217,7 +11509,7 @@ type ListLuckyGiftConfigsRequest struct { func (x *ListLuckyGiftConfigsRequest) Reset() { *x = ListLuckyGiftConfigsRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[137] + mi := &file_proto_activity_v1_activity_proto_msgTypes[140] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11229,7 +11521,7 @@ func (x *ListLuckyGiftConfigsRequest) String() string { func (*ListLuckyGiftConfigsRequest) ProtoMessage() {} func (x *ListLuckyGiftConfigsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[137] + mi := &file_proto_activity_v1_activity_proto_msgTypes[140] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11242,7 +11534,7 @@ func (x *ListLuckyGiftConfigsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLuckyGiftConfigsRequest.ProtoReflect.Descriptor instead. func (*ListLuckyGiftConfigsRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{137} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{140} } func (x *ListLuckyGiftConfigsRequest) GetMeta() *RequestMeta { @@ -11254,14 +11546,14 @@ func (x *ListLuckyGiftConfigsRequest) GetMeta() *RequestMeta { type ListLuckyGiftConfigsResponse struct { state protoimpl.MessageState `protogen:"open.v1"` - Configs []*LuckyGiftConfig `protobuf:"bytes,1,rep,name=configs,proto3" json:"configs,omitempty"` + Configs []*LuckyGiftRuleConfig `protobuf:"bytes,1,rep,name=configs,proto3" json:"configs,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } func (x *ListLuckyGiftConfigsResponse) Reset() { *x = ListLuckyGiftConfigsResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[138] + mi := &file_proto_activity_v1_activity_proto_msgTypes[141] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11273,7 +11565,7 @@ func (x *ListLuckyGiftConfigsResponse) String() string { func (*ListLuckyGiftConfigsResponse) ProtoMessage() {} func (x *ListLuckyGiftConfigsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[138] + mi := &file_proto_activity_v1_activity_proto_msgTypes[141] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11286,10 +11578,10 @@ func (x *ListLuckyGiftConfigsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLuckyGiftConfigsResponse.ProtoReflect.Descriptor instead. func (*ListLuckyGiftConfigsResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{138} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{141} } -func (x *ListLuckyGiftConfigsResponse) GetConfigs() []*LuckyGiftConfig { +func (x *ListLuckyGiftConfigsResponse) GetConfigs() []*LuckyGiftRuleConfig { if x != nil { return x.Configs } @@ -11312,7 +11604,7 @@ type ListLuckyGiftDrawsRequest struct { func (x *ListLuckyGiftDrawsRequest) Reset() { *x = ListLuckyGiftDrawsRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[139] + mi := &file_proto_activity_v1_activity_proto_msgTypes[142] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11324,7 +11616,7 @@ func (x *ListLuckyGiftDrawsRequest) String() string { func (*ListLuckyGiftDrawsRequest) ProtoMessage() {} func (x *ListLuckyGiftDrawsRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[139] + mi := &file_proto_activity_v1_activity_proto_msgTypes[142] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11337,7 +11629,7 @@ func (x *ListLuckyGiftDrawsRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLuckyGiftDrawsRequest.ProtoReflect.Descriptor instead. func (*ListLuckyGiftDrawsRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{139} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{142} } func (x *ListLuckyGiftDrawsRequest) GetMeta() *RequestMeta { @@ -11406,7 +11698,7 @@ type ListLuckyGiftDrawsResponse struct { func (x *ListLuckyGiftDrawsResponse) Reset() { *x = ListLuckyGiftDrawsResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[140] + mi := &file_proto_activity_v1_activity_proto_msgTypes[143] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11418,7 +11710,7 @@ func (x *ListLuckyGiftDrawsResponse) String() string { func (*ListLuckyGiftDrawsResponse) ProtoMessage() {} func (x *ListLuckyGiftDrawsResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[140] + mi := &file_proto_activity_v1_activity_proto_msgTypes[143] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11431,7 +11723,7 @@ func (x *ListLuckyGiftDrawsResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ListLuckyGiftDrawsResponse.ProtoReflect.Descriptor instead. func (*ListLuckyGiftDrawsResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{140} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{143} } func (x *ListLuckyGiftDrawsResponse) GetDraws() []*LuckyGiftDrawResult { @@ -11469,7 +11761,7 @@ type LuckyGiftDrawSummary struct { func (x *LuckyGiftDrawSummary) Reset() { *x = LuckyGiftDrawSummary{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[141] + mi := &file_proto_activity_v1_activity_proto_msgTypes[144] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11481,7 +11773,7 @@ func (x *LuckyGiftDrawSummary) String() string { func (*LuckyGiftDrawSummary) ProtoMessage() {} func (x *LuckyGiftDrawSummary) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[141] + mi := &file_proto_activity_v1_activity_proto_msgTypes[144] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11494,7 +11786,7 @@ func (x *LuckyGiftDrawSummary) ProtoReflect() protoreflect.Message { // Deprecated: Use LuckyGiftDrawSummary.ProtoReflect.Descriptor instead. func (*LuckyGiftDrawSummary) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{141} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{144} } func (x *LuckyGiftDrawSummary) GetPoolId() string { @@ -11602,7 +11894,7 @@ type GetLuckyGiftDrawSummaryRequest struct { func (x *GetLuckyGiftDrawSummaryRequest) Reset() { *x = GetLuckyGiftDrawSummaryRequest{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[142] + mi := &file_proto_activity_v1_activity_proto_msgTypes[145] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11614,7 +11906,7 @@ func (x *GetLuckyGiftDrawSummaryRequest) String() string { func (*GetLuckyGiftDrawSummaryRequest) ProtoMessage() {} func (x *GetLuckyGiftDrawSummaryRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[142] + mi := &file_proto_activity_v1_activity_proto_msgTypes[145] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11627,7 +11919,7 @@ func (x *GetLuckyGiftDrawSummaryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLuckyGiftDrawSummaryRequest.ProtoReflect.Descriptor instead. func (*GetLuckyGiftDrawSummaryRequest) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{142} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{145} } func (x *GetLuckyGiftDrawSummaryRequest) GetMeta() *RequestMeta { @@ -11681,7 +11973,7 @@ type GetLuckyGiftDrawSummaryResponse struct { func (x *GetLuckyGiftDrawSummaryResponse) Reset() { *x = GetLuckyGiftDrawSummaryResponse{} - mi := &file_proto_activity_v1_activity_proto_msgTypes[143] + mi := &file_proto_activity_v1_activity_proto_msgTypes[146] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -11693,7 +11985,7 @@ func (x *GetLuckyGiftDrawSummaryResponse) String() string { func (*GetLuckyGiftDrawSummaryResponse) ProtoMessage() {} func (x *GetLuckyGiftDrawSummaryResponse) ProtoReflect() protoreflect.Message { - mi := &file_proto_activity_v1_activity_proto_msgTypes[143] + mi := &file_proto_activity_v1_activity_proto_msgTypes[146] if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -11706,7 +11998,7 @@ func (x *GetLuckyGiftDrawSummaryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use GetLuckyGiftDrawSummaryResponse.ProtoReflect.Descriptor instead. func (*GetLuckyGiftDrawSummaryResponse) Descriptor() ([]byte, []int) { - return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{143} + return file_proto_activity_v1_activity_proto_rawDescGZIP(), []int{146} } func (x *GetLuckyGiftDrawSummaryResponse) GetSummary() *LuckyGiftDrawSummary { @@ -12694,7 +12986,34 @@ const file_proto_activity_v1_activity_proto_rawDesc = "" + "\rcreated_at_ms\x18% \x01(\x03R\vcreatedAtMs\x12\"\n" + "\rupdated_at_ms\x18& \x01(\x03R\vupdatedAtMs\x12\x17\n" + "\apool_id\x18' \x01(\tR\x06poolId\x12'\n" + - "\x0fmultiplier_ppms\x18( \x03(\x03R\x0emultiplierPpms\"\xaf\x01\n" + + "\x0fmultiplier_ppms\x18( \x03(\x03R\x0emultiplierPpms\"\xa1\x02\n" + + "\x11LuckyGiftRuleTier\x12\x14\n" + + "\x05stage\x18\x01 \x01(\tR\x05stage\x12\x17\n" + + "\atier_id\x18\x02 \x01(\tR\x06tierId\x12%\n" + + "\x0emultiplier_ppm\x18\x03 \x01(\x03R\rmultiplierPpm\x12&\n" + + "\x0fbase_weight_ppm\x18\x04 \x01(\x03R\rbaseWeightPpm\x12#\n" + + "\rreward_source\x18\x05 \x01(\tR\frewardSource\x12&\n" + + "\x0fhigh_water_only\x18\x06 \x01(\bR\rhighWaterOnly\x12'\n" + + "\x0fbroadcast_level\x18\a \x01(\tR\x0ebroadcastLevel\x12\x18\n" + + "\aenabled\x18\b \x01(\bR\aenabled\"f\n" + + "\x12LuckyGiftRuleStage\x12\x14\n" + + "\x05stage\x18\x01 \x01(\tR\x05stage\x12:\n" + + "\x05tiers\x18\x02 \x03(\v2$.hyapp.activity.v1.LuckyGiftRuleTierR\x05tiers\"\xa2\x04\n" + + "\x13LuckyGiftRuleConfig\x12\x19\n" + + "\bapp_code\x18\x01 \x01(\tR\aappCode\x12\x17\n" + + "\apool_id\x18\x02 \x01(\tR\x06poolId\x12!\n" + + "\frule_version\x18\x03 \x01(\x03R\vruleVersion\x12\x18\n" + + "\aenabled\x18\x04 \x01(\bR\aenabled\x12$\n" + + "\x0etarget_rtp_ppm\x18\x05 \x01(\x03R\ftargetRtpPpm\x12\"\n" + + "\rpool_rate_ppm\x18\x06 \x01(\x03R\vpoolRatePpm\x126\n" + + "\x17settlement_window_wager\x18\a \x01(\x03R\x15settlementWindowWager\x12(\n" + + "\x10control_band_ppm\x18\b \x01(\x03R\x0econtrolBandPpm\x120\n" + + "\x14gift_price_reference\x18\t \x01(\x03R\x12giftPriceReference\x12*\n" + + "\x11effective_from_ms\x18\n" + + " \x01(\x03R\x0feffectiveFromMs\x12-\n" + + "\x13created_by_admin_id\x18\v \x01(\x03R\x10createdByAdminId\x12\"\n" + + "\rcreated_at_ms\x18\f \x01(\x03R\vcreatedAtMs\x12=\n" + + "\x06stages\x18\r \x03(\v2%.hyapp.activity.v1.LuckyGiftRuleStageR\x06stages\"\xaf\x01\n" + "\x15CheckLuckyGiftRequest\x122\n" + "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\x12\x17\n" + "\auser_id\x18\x02 \x01(\x03R\x06userId\x12\x17\n" + @@ -12743,19 +13062,19 @@ const file_proto_activity_v1_activity_proto_rawDesc = "" + "\x19GetLuckyGiftConfigRequest\x122\n" + "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\x12\x17\n" + "\agift_id\x18\x02 \x01(\tR\x06giftId\x12\x17\n" + - "\apool_id\x18\x03 \x01(\tR\x06poolId\"X\n" + - "\x1aGetLuckyGiftConfigResponse\x12:\n" + - "\x06config\x18\x01 \x01(\v2\".hyapp.activity.v1.LuckyGiftConfigR\x06config\"\xba\x01\n" + + "\apool_id\x18\x03 \x01(\tR\x06poolId\"\\\n" + + "\x1aGetLuckyGiftConfigResponse\x12>\n" + + "\x06config\x18\x01 \x01(\v2&.hyapp.activity.v1.LuckyGiftRuleConfigR\x06config\"\xbe\x01\n" + "\x1cUpsertLuckyGiftConfigRequest\x122\n" + - "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\x12:\n" + - "\x06config\x18\x02 \x01(\v2\".hyapp.activity.v1.LuckyGiftConfigR\x06config\x12*\n" + - "\x11operator_admin_id\x18\x03 \x01(\x03R\x0foperatorAdminId\"[\n" + - "\x1dUpsertLuckyGiftConfigResponse\x12:\n" + - "\x06config\x18\x01 \x01(\v2\".hyapp.activity.v1.LuckyGiftConfigR\x06config\"Q\n" + + "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\x12>\n" + + "\x06config\x18\x02 \x01(\v2&.hyapp.activity.v1.LuckyGiftRuleConfigR\x06config\x12*\n" + + "\x11operator_admin_id\x18\x03 \x01(\x03R\x0foperatorAdminId\"_\n" + + "\x1dUpsertLuckyGiftConfigResponse\x12>\n" + + "\x06config\x18\x01 \x01(\v2&.hyapp.activity.v1.LuckyGiftRuleConfigR\x06config\"Q\n" + "\x1bListLuckyGiftConfigsRequest\x122\n" + - "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\"\\\n" + - "\x1cListLuckyGiftConfigsResponse\x12<\n" + - "\aconfigs\x18\x01 \x03(\v2\".hyapp.activity.v1.LuckyGiftConfigR\aconfigs\"\xfc\x01\n" + + "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\"`\n" + + "\x1cListLuckyGiftConfigsResponse\x12@\n" + + "\aconfigs\x18\x01 \x03(\v2&.hyapp.activity.v1.LuckyGiftRuleConfigR\aconfigs\"\xfc\x01\n" + "\x19ListLuckyGiftDrawsRequest\x122\n" + "\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\x12\x17\n" + "\agift_id\x18\x02 \x01(\tR\x06giftId\x12\x17\n" + @@ -12885,7 +13204,7 @@ func file_proto_activity_v1_activity_proto_rawDescGZIP() []byte { return file_proto_activity_v1_activity_proto_rawDescData } -var file_proto_activity_v1_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 144) +var file_proto_activity_v1_activity_proto_msgTypes = make([]protoimpl.MessageInfo, 147) var file_proto_activity_v1_activity_proto_goTypes = []any{ (*RequestMeta)(nil), // 0: hyapp.activity.v1.RequestMeta (*PingActivityRequest)(nil), // 1: hyapp.activity.v1.PingActivityRequest @@ -13015,23 +13334,26 @@ var file_proto_activity_v1_activity_proto_goTypes = []any{ (*LuckyGiftMeta)(nil), // 125: hyapp.activity.v1.LuckyGiftMeta (*LuckyGiftTier)(nil), // 126: hyapp.activity.v1.LuckyGiftTier (*LuckyGiftConfig)(nil), // 127: hyapp.activity.v1.LuckyGiftConfig - (*CheckLuckyGiftRequest)(nil), // 128: hyapp.activity.v1.CheckLuckyGiftRequest - (*CheckLuckyGiftResponse)(nil), // 129: hyapp.activity.v1.CheckLuckyGiftResponse - (*LuckyGiftDrawResult)(nil), // 130: hyapp.activity.v1.LuckyGiftDrawResult - (*ExecuteLuckyGiftDrawRequest)(nil), // 131: hyapp.activity.v1.ExecuteLuckyGiftDrawRequest - (*ExecuteLuckyGiftDrawResponse)(nil), // 132: hyapp.activity.v1.ExecuteLuckyGiftDrawResponse - (*GetLuckyGiftConfigRequest)(nil), // 133: hyapp.activity.v1.GetLuckyGiftConfigRequest - (*GetLuckyGiftConfigResponse)(nil), // 134: hyapp.activity.v1.GetLuckyGiftConfigResponse - (*UpsertLuckyGiftConfigRequest)(nil), // 135: hyapp.activity.v1.UpsertLuckyGiftConfigRequest - (*UpsertLuckyGiftConfigResponse)(nil), // 136: hyapp.activity.v1.UpsertLuckyGiftConfigResponse - (*ListLuckyGiftConfigsRequest)(nil), // 137: hyapp.activity.v1.ListLuckyGiftConfigsRequest - (*ListLuckyGiftConfigsResponse)(nil), // 138: hyapp.activity.v1.ListLuckyGiftConfigsResponse - (*ListLuckyGiftDrawsRequest)(nil), // 139: hyapp.activity.v1.ListLuckyGiftDrawsRequest - (*ListLuckyGiftDrawsResponse)(nil), // 140: hyapp.activity.v1.ListLuckyGiftDrawsResponse - (*LuckyGiftDrawSummary)(nil), // 141: hyapp.activity.v1.LuckyGiftDrawSummary - (*GetLuckyGiftDrawSummaryRequest)(nil), // 142: hyapp.activity.v1.GetLuckyGiftDrawSummaryRequest - (*GetLuckyGiftDrawSummaryResponse)(nil), // 143: hyapp.activity.v1.GetLuckyGiftDrawSummaryResponse - (*v1.EventEnvelope)(nil), // 144: hyapp.events.room.v1.EventEnvelope + (*LuckyGiftRuleTier)(nil), // 128: hyapp.activity.v1.LuckyGiftRuleTier + (*LuckyGiftRuleStage)(nil), // 129: hyapp.activity.v1.LuckyGiftRuleStage + (*LuckyGiftRuleConfig)(nil), // 130: hyapp.activity.v1.LuckyGiftRuleConfig + (*CheckLuckyGiftRequest)(nil), // 131: hyapp.activity.v1.CheckLuckyGiftRequest + (*CheckLuckyGiftResponse)(nil), // 132: hyapp.activity.v1.CheckLuckyGiftResponse + (*LuckyGiftDrawResult)(nil), // 133: hyapp.activity.v1.LuckyGiftDrawResult + (*ExecuteLuckyGiftDrawRequest)(nil), // 134: hyapp.activity.v1.ExecuteLuckyGiftDrawRequest + (*ExecuteLuckyGiftDrawResponse)(nil), // 135: hyapp.activity.v1.ExecuteLuckyGiftDrawResponse + (*GetLuckyGiftConfigRequest)(nil), // 136: hyapp.activity.v1.GetLuckyGiftConfigRequest + (*GetLuckyGiftConfigResponse)(nil), // 137: hyapp.activity.v1.GetLuckyGiftConfigResponse + (*UpsertLuckyGiftConfigRequest)(nil), // 138: hyapp.activity.v1.UpsertLuckyGiftConfigRequest + (*UpsertLuckyGiftConfigResponse)(nil), // 139: hyapp.activity.v1.UpsertLuckyGiftConfigResponse + (*ListLuckyGiftConfigsRequest)(nil), // 140: hyapp.activity.v1.ListLuckyGiftConfigsRequest + (*ListLuckyGiftConfigsResponse)(nil), // 141: hyapp.activity.v1.ListLuckyGiftConfigsResponse + (*ListLuckyGiftDrawsRequest)(nil), // 142: hyapp.activity.v1.ListLuckyGiftDrawsRequest + (*ListLuckyGiftDrawsResponse)(nil), // 143: hyapp.activity.v1.ListLuckyGiftDrawsResponse + (*LuckyGiftDrawSummary)(nil), // 144: hyapp.activity.v1.LuckyGiftDrawSummary + (*GetLuckyGiftDrawSummaryRequest)(nil), // 145: hyapp.activity.v1.GetLuckyGiftDrawSummaryRequest + (*GetLuckyGiftDrawSummaryResponse)(nil), // 146: hyapp.activity.v1.GetLuckyGiftDrawSummaryResponse + (*v1.EventEnvelope)(nil), // 147: hyapp.events.room.v1.EventEnvelope } var file_proto_activity_v1_activity_proto_depIdxs = []int32{ 0, // 0: hyapp.activity.v1.PingActivityRequest.meta:type_name -> hyapp.activity.v1.RequestMeta @@ -13056,7 +13378,7 @@ var file_proto_activity_v1_activity_proto_depIdxs = []int32{ 0, // 19: hyapp.activity.v1.PublishGlobalBroadcastRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 0, // 20: hyapp.activity.v1.RemoveRegionBroadcastMemberRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 0, // 21: hyapp.activity.v1.ConsumeRoomEventRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 144, // 22: hyapp.activity.v1.ConsumeRoomEventRequest.envelope:type_name -> hyapp.events.room.v1.EventEnvelope + 147, // 22: hyapp.activity.v1.ConsumeRoomEventRequest.envelope:type_name -> hyapp.events.room.v1.EventEnvelope 0, // 23: hyapp.activity.v1.ListTaskDefinitionsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta 42, // 24: hyapp.activity.v1.ListTaskDefinitionsResponse.tasks:type_name -> hyapp.activity.v1.TaskDefinition 0, // 25: hyapp.activity.v1.UpsertTaskDefinitionRequest.meta:type_name -> hyapp.activity.v1.RequestMeta @@ -13135,145 +13457,147 @@ var file_proto_activity_v1_activity_proto_depIdxs = []int32{ 112, // 98: hyapp.activity.v1.UpsertAchievementDefinitionResponse.achievement:type_name -> hyapp.activity.v1.AchievementDefinition 0, // 99: hyapp.activity.v1.LuckyGiftMeta.meta:type_name -> hyapp.activity.v1.RequestMeta 126, // 100: hyapp.activity.v1.LuckyGiftConfig.tiers:type_name -> hyapp.activity.v1.LuckyGiftTier - 0, // 101: hyapp.activity.v1.CheckLuckyGiftRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 125, // 102: hyapp.activity.v1.ExecuteLuckyGiftDrawRequest.lucky_gift:type_name -> hyapp.activity.v1.LuckyGiftMeta - 130, // 103: hyapp.activity.v1.ExecuteLuckyGiftDrawResponse.result:type_name -> hyapp.activity.v1.LuckyGiftDrawResult - 0, // 104: hyapp.activity.v1.GetLuckyGiftConfigRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 127, // 105: hyapp.activity.v1.GetLuckyGiftConfigResponse.config:type_name -> hyapp.activity.v1.LuckyGiftConfig - 0, // 106: hyapp.activity.v1.UpsertLuckyGiftConfigRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 127, // 107: hyapp.activity.v1.UpsertLuckyGiftConfigRequest.config:type_name -> hyapp.activity.v1.LuckyGiftConfig - 127, // 108: hyapp.activity.v1.UpsertLuckyGiftConfigResponse.config:type_name -> hyapp.activity.v1.LuckyGiftConfig - 0, // 109: hyapp.activity.v1.ListLuckyGiftConfigsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 127, // 110: hyapp.activity.v1.ListLuckyGiftConfigsResponse.configs:type_name -> hyapp.activity.v1.LuckyGiftConfig - 0, // 111: hyapp.activity.v1.ListLuckyGiftDrawsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 130, // 112: hyapp.activity.v1.ListLuckyGiftDrawsResponse.draws:type_name -> hyapp.activity.v1.LuckyGiftDrawResult - 0, // 113: hyapp.activity.v1.GetLuckyGiftDrawSummaryRequest.meta:type_name -> hyapp.activity.v1.RequestMeta - 141, // 114: hyapp.activity.v1.GetLuckyGiftDrawSummaryResponse.summary:type_name -> hyapp.activity.v1.LuckyGiftDrawSummary - 1, // 115: hyapp.activity.v1.ActivityService.PingActivity:input_type -> hyapp.activity.v1.PingActivityRequest - 3, // 116: hyapp.activity.v1.ActivityService.GetActivityStatus:input_type -> hyapp.activity.v1.GetActivityStatusRequest - 6, // 117: hyapp.activity.v1.MessageInboxService.ListMessageTabs:input_type -> hyapp.activity.v1.ListMessageTabsRequest - 9, // 118: hyapp.activity.v1.MessageInboxService.ListInboxMessages:input_type -> hyapp.activity.v1.ListInboxMessagesRequest - 11, // 119: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:input_type -> hyapp.activity.v1.MarkInboxMessageReadRequest - 13, // 120: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:input_type -> hyapp.activity.v1.MarkInboxSectionReadRequest - 15, // 121: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:input_type -> hyapp.activity.v1.DeleteInboxMessageRequest - 17, // 122: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:input_type -> hyapp.activity.v1.CreateInboxMessageRequest - 19, // 123: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:input_type -> hyapp.activity.v1.CreateFanoutJobRequest - 21, // 124: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:input_type -> hyapp.activity.v1.CronBatchRequest - 21, // 125: hyapp.activity.v1.ActivityCronService.ProcessLevelRewardBatch:input_type -> hyapp.activity.v1.CronBatchRequest - 21, // 126: hyapp.activity.v1.ActivityCronService.ProcessAchievementRewardBatch:input_type -> hyapp.activity.v1.CronBatchRequest - 25, // 127: hyapp.activity.v1.TaskService.ListUserTasks:input_type -> hyapp.activity.v1.ListUserTasksRequest - 27, // 128: hyapp.activity.v1.TaskService.ClaimTaskReward:input_type -> hyapp.activity.v1.ClaimTaskRewardRequest - 29, // 129: hyapp.activity.v1.TaskService.ConsumeTaskEvent:input_type -> hyapp.activity.v1.ConsumeTaskEventRequest - 94, // 130: hyapp.activity.v1.GrowthLevelService.GetMyLevelOverview:input_type -> hyapp.activity.v1.GetMyLevelOverviewRequest - 96, // 131: hyapp.activity.v1.GrowthLevelService.GetLevelTrack:input_type -> hyapp.activity.v1.GetLevelTrackRequest - 99, // 132: hyapp.activity.v1.GrowthLevelService.ListLevelRewards:input_type -> hyapp.activity.v1.ListLevelRewardsRequest - 101, // 133: hyapp.activity.v1.GrowthLevelService.ConsumeLevelEvent:input_type -> hyapp.activity.v1.ConsumeLevelEventRequest - 114, // 134: hyapp.activity.v1.AchievementService.ListAchievements:input_type -> hyapp.activity.v1.ListAchievementsRequest - 116, // 135: hyapp.activity.v1.AchievementService.ConsumeAchievementEvent:input_type -> hyapp.activity.v1.ConsumeAchievementEventRequest - 119, // 136: hyapp.activity.v1.AchievementService.ListMyBadges:input_type -> hyapp.activity.v1.ListMyBadgesRequest - 121, // 137: hyapp.activity.v1.AchievementService.SetBadgeDisplay:input_type -> hyapp.activity.v1.SetBadgeDisplayRequest - 128, // 138: hyapp.activity.v1.LuckyGiftService.CheckLuckyGift:input_type -> hyapp.activity.v1.CheckLuckyGiftRequest - 131, // 139: hyapp.activity.v1.LuckyGiftService.ExecuteLuckyGiftDraw:input_type -> hyapp.activity.v1.ExecuteLuckyGiftDrawRequest - 32, // 140: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:input_type -> hyapp.activity.v1.EnsureBroadcastGroupsRequest - 34, // 141: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:input_type -> hyapp.activity.v1.PublishRegionBroadcastRequest - 35, // 142: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:input_type -> hyapp.activity.v1.PublishGlobalBroadcastRequest - 37, // 143: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:input_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberRequest - 21, // 144: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:input_type -> hyapp.activity.v1.CronBatchRequest - 40, // 145: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:input_type -> hyapp.activity.v1.ConsumeRoomEventRequest - 43, // 146: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:input_type -> hyapp.activity.v1.ListTaskDefinitionsRequest - 45, // 147: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:input_type -> hyapp.activity.v1.UpsertTaskDefinitionRequest - 47, // 148: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:input_type -> hyapp.activity.v1.SetTaskDefinitionStatusRequest - 52, // 149: hyapp.activity.v1.RegistrationRewardService.GetRegistrationRewardEligibility:input_type -> hyapp.activity.v1.GetRegistrationRewardEligibilityRequest - 54, // 150: hyapp.activity.v1.RegistrationRewardService.IssueRegistrationReward:input_type -> hyapp.activity.v1.IssueRegistrationRewardRequest - 56, // 151: hyapp.activity.v1.AdminRegistrationRewardService.GetRegistrationRewardConfig:input_type -> hyapp.activity.v1.GetRegistrationRewardConfigRequest - 58, // 152: hyapp.activity.v1.AdminRegistrationRewardService.UpdateRegistrationRewardConfig:input_type -> hyapp.activity.v1.UpdateRegistrationRewardConfigRequest - 60, // 153: hyapp.activity.v1.AdminRegistrationRewardService.ListRegistrationRewardClaims:input_type -> hyapp.activity.v1.ListRegistrationRewardClaimsRequest - 66, // 154: hyapp.activity.v1.FirstRechargeRewardService.GetFirstRechargeRewardStatus:input_type -> hyapp.activity.v1.GetFirstRechargeRewardStatusRequest - 68, // 155: hyapp.activity.v1.FirstRechargeRewardService.ConsumeFirstRechargeReward:input_type -> hyapp.activity.v1.ConsumeFirstRechargeRewardRequest - 70, // 156: hyapp.activity.v1.AdminFirstRechargeRewardService.GetFirstRechargeRewardConfig:input_type -> hyapp.activity.v1.GetFirstRechargeRewardConfigRequest - 72, // 157: hyapp.activity.v1.AdminFirstRechargeRewardService.UpdateFirstRechargeRewardConfig:input_type -> hyapp.activity.v1.UpdateFirstRechargeRewardConfigRequest - 74, // 158: hyapp.activity.v1.AdminFirstRechargeRewardService.ListFirstRechargeRewardClaims:input_type -> hyapp.activity.v1.ListFirstRechargeRewardClaimsRequest - 79, // 159: hyapp.activity.v1.SevenDayCheckInService.GetSevenDayCheckInStatus:input_type -> hyapp.activity.v1.GetSevenDayCheckInStatusRequest - 81, // 160: hyapp.activity.v1.SevenDayCheckInService.SignSevenDayCheckIn:input_type -> hyapp.activity.v1.SignSevenDayCheckInRequest - 83, // 161: hyapp.activity.v1.AdminSevenDayCheckInService.GetSevenDayCheckInConfig:input_type -> hyapp.activity.v1.GetSevenDayCheckInConfigRequest - 85, // 162: hyapp.activity.v1.AdminSevenDayCheckInService.UpdateSevenDayCheckInConfig:input_type -> hyapp.activity.v1.UpdateSevenDayCheckInConfigRequest - 88, // 163: hyapp.activity.v1.AdminSevenDayCheckInService.ListSevenDayCheckInClaims:input_type -> hyapp.activity.v1.ListSevenDayCheckInClaimsRequest - 109, // 164: hyapp.activity.v1.AdminGrowthLevelService.ListLevelConfig:input_type -> hyapp.activity.v1.ListLevelConfigRequest - 103, // 165: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTrack:input_type -> hyapp.activity.v1.UpsertLevelTrackRequest - 105, // 166: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelRule:input_type -> hyapp.activity.v1.UpsertLevelRuleRequest - 107, // 167: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTier:input_type -> hyapp.activity.v1.UpsertLevelTierRequest - 114, // 168: hyapp.activity.v1.AdminAchievementService.ListAchievementDefinitions:input_type -> hyapp.activity.v1.ListAchievementsRequest - 123, // 169: hyapp.activity.v1.AdminAchievementService.UpsertAchievementDefinition:input_type -> hyapp.activity.v1.UpsertAchievementDefinitionRequest - 133, // 170: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftConfig:input_type -> hyapp.activity.v1.GetLuckyGiftConfigRequest - 135, // 171: hyapp.activity.v1.AdminLuckyGiftService.UpsertLuckyGiftConfig:input_type -> hyapp.activity.v1.UpsertLuckyGiftConfigRequest - 137, // 172: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftConfigs:input_type -> hyapp.activity.v1.ListLuckyGiftConfigsRequest - 139, // 173: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftDraws:input_type -> hyapp.activity.v1.ListLuckyGiftDrawsRequest - 142, // 174: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftDrawSummary:input_type -> hyapp.activity.v1.GetLuckyGiftDrawSummaryRequest - 2, // 175: hyapp.activity.v1.ActivityService.PingActivity:output_type -> hyapp.activity.v1.PingActivityResponse - 4, // 176: hyapp.activity.v1.ActivityService.GetActivityStatus:output_type -> hyapp.activity.v1.GetActivityStatusResponse - 7, // 177: hyapp.activity.v1.MessageInboxService.ListMessageTabs:output_type -> hyapp.activity.v1.ListMessageTabsResponse - 10, // 178: hyapp.activity.v1.MessageInboxService.ListInboxMessages:output_type -> hyapp.activity.v1.ListInboxMessagesResponse - 12, // 179: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:output_type -> hyapp.activity.v1.MarkInboxMessageReadResponse - 14, // 180: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:output_type -> hyapp.activity.v1.MarkInboxSectionReadResponse - 16, // 181: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:output_type -> hyapp.activity.v1.DeleteInboxMessageResponse - 18, // 182: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:output_type -> hyapp.activity.v1.CreateInboxMessageResponse - 20, // 183: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:output_type -> hyapp.activity.v1.CreateFanoutJobResponse - 22, // 184: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:output_type -> hyapp.activity.v1.CronBatchResponse - 22, // 185: hyapp.activity.v1.ActivityCronService.ProcessLevelRewardBatch:output_type -> hyapp.activity.v1.CronBatchResponse - 22, // 186: hyapp.activity.v1.ActivityCronService.ProcessAchievementRewardBatch:output_type -> hyapp.activity.v1.CronBatchResponse - 26, // 187: hyapp.activity.v1.TaskService.ListUserTasks:output_type -> hyapp.activity.v1.ListUserTasksResponse - 28, // 188: hyapp.activity.v1.TaskService.ClaimTaskReward:output_type -> hyapp.activity.v1.ClaimTaskRewardResponse - 30, // 189: hyapp.activity.v1.TaskService.ConsumeTaskEvent:output_type -> hyapp.activity.v1.ConsumeTaskEventResponse - 95, // 190: hyapp.activity.v1.GrowthLevelService.GetMyLevelOverview:output_type -> hyapp.activity.v1.GetMyLevelOverviewResponse - 97, // 191: hyapp.activity.v1.GrowthLevelService.GetLevelTrack:output_type -> hyapp.activity.v1.GetLevelTrackResponse - 100, // 192: hyapp.activity.v1.GrowthLevelService.ListLevelRewards:output_type -> hyapp.activity.v1.ListLevelRewardsResponse - 102, // 193: hyapp.activity.v1.GrowthLevelService.ConsumeLevelEvent:output_type -> hyapp.activity.v1.ConsumeLevelEventResponse - 115, // 194: hyapp.activity.v1.AchievementService.ListAchievements:output_type -> hyapp.activity.v1.ListAchievementsResponse - 117, // 195: hyapp.activity.v1.AchievementService.ConsumeAchievementEvent:output_type -> hyapp.activity.v1.ConsumeAchievementEventResponse - 120, // 196: hyapp.activity.v1.AchievementService.ListMyBadges:output_type -> hyapp.activity.v1.ListMyBadgesResponse - 122, // 197: hyapp.activity.v1.AchievementService.SetBadgeDisplay:output_type -> hyapp.activity.v1.SetBadgeDisplayResponse - 129, // 198: hyapp.activity.v1.LuckyGiftService.CheckLuckyGift:output_type -> hyapp.activity.v1.CheckLuckyGiftResponse - 132, // 199: hyapp.activity.v1.LuckyGiftService.ExecuteLuckyGiftDraw:output_type -> hyapp.activity.v1.ExecuteLuckyGiftDrawResponse - 33, // 200: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:output_type -> hyapp.activity.v1.EnsureBroadcastGroupsResponse - 36, // 201: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse - 36, // 202: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse - 38, // 203: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:output_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberResponse - 39, // 204: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:output_type -> hyapp.activity.v1.ProcessBroadcastOutboxBatchResponse - 41, // 205: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:output_type -> hyapp.activity.v1.ConsumeRoomEventResponse - 44, // 206: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:output_type -> hyapp.activity.v1.ListTaskDefinitionsResponse - 46, // 207: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:output_type -> hyapp.activity.v1.UpsertTaskDefinitionResponse - 48, // 208: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:output_type -> hyapp.activity.v1.SetTaskDefinitionStatusResponse - 53, // 209: hyapp.activity.v1.RegistrationRewardService.GetRegistrationRewardEligibility:output_type -> hyapp.activity.v1.GetRegistrationRewardEligibilityResponse - 55, // 210: hyapp.activity.v1.RegistrationRewardService.IssueRegistrationReward:output_type -> hyapp.activity.v1.IssueRegistrationRewardResponse - 57, // 211: hyapp.activity.v1.AdminRegistrationRewardService.GetRegistrationRewardConfig:output_type -> hyapp.activity.v1.GetRegistrationRewardConfigResponse - 59, // 212: hyapp.activity.v1.AdminRegistrationRewardService.UpdateRegistrationRewardConfig:output_type -> hyapp.activity.v1.UpdateRegistrationRewardConfigResponse - 61, // 213: hyapp.activity.v1.AdminRegistrationRewardService.ListRegistrationRewardClaims:output_type -> hyapp.activity.v1.ListRegistrationRewardClaimsResponse - 67, // 214: hyapp.activity.v1.FirstRechargeRewardService.GetFirstRechargeRewardStatus:output_type -> hyapp.activity.v1.GetFirstRechargeRewardStatusResponse - 69, // 215: hyapp.activity.v1.FirstRechargeRewardService.ConsumeFirstRechargeReward:output_type -> hyapp.activity.v1.ConsumeFirstRechargeRewardResponse - 71, // 216: hyapp.activity.v1.AdminFirstRechargeRewardService.GetFirstRechargeRewardConfig:output_type -> hyapp.activity.v1.GetFirstRechargeRewardConfigResponse - 73, // 217: hyapp.activity.v1.AdminFirstRechargeRewardService.UpdateFirstRechargeRewardConfig:output_type -> hyapp.activity.v1.UpdateFirstRechargeRewardConfigResponse - 75, // 218: hyapp.activity.v1.AdminFirstRechargeRewardService.ListFirstRechargeRewardClaims:output_type -> hyapp.activity.v1.ListFirstRechargeRewardClaimsResponse - 80, // 219: hyapp.activity.v1.SevenDayCheckInService.GetSevenDayCheckInStatus:output_type -> hyapp.activity.v1.GetSevenDayCheckInStatusResponse - 82, // 220: hyapp.activity.v1.SevenDayCheckInService.SignSevenDayCheckIn:output_type -> hyapp.activity.v1.SignSevenDayCheckInResponse - 84, // 221: hyapp.activity.v1.AdminSevenDayCheckInService.GetSevenDayCheckInConfig:output_type -> hyapp.activity.v1.GetSevenDayCheckInConfigResponse - 86, // 222: hyapp.activity.v1.AdminSevenDayCheckInService.UpdateSevenDayCheckInConfig:output_type -> hyapp.activity.v1.UpdateSevenDayCheckInConfigResponse - 89, // 223: hyapp.activity.v1.AdminSevenDayCheckInService.ListSevenDayCheckInClaims:output_type -> hyapp.activity.v1.ListSevenDayCheckInClaimsResponse - 110, // 224: hyapp.activity.v1.AdminGrowthLevelService.ListLevelConfig:output_type -> hyapp.activity.v1.ListLevelConfigResponse - 104, // 225: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTrack:output_type -> hyapp.activity.v1.UpsertLevelTrackResponse - 106, // 226: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelRule:output_type -> hyapp.activity.v1.UpsertLevelRuleResponse - 108, // 227: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTier:output_type -> hyapp.activity.v1.UpsertLevelTierResponse - 115, // 228: hyapp.activity.v1.AdminAchievementService.ListAchievementDefinitions:output_type -> hyapp.activity.v1.ListAchievementsResponse - 124, // 229: hyapp.activity.v1.AdminAchievementService.UpsertAchievementDefinition:output_type -> hyapp.activity.v1.UpsertAchievementDefinitionResponse - 134, // 230: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftConfig:output_type -> hyapp.activity.v1.GetLuckyGiftConfigResponse - 136, // 231: hyapp.activity.v1.AdminLuckyGiftService.UpsertLuckyGiftConfig:output_type -> hyapp.activity.v1.UpsertLuckyGiftConfigResponse - 138, // 232: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftConfigs:output_type -> hyapp.activity.v1.ListLuckyGiftConfigsResponse - 140, // 233: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftDraws:output_type -> hyapp.activity.v1.ListLuckyGiftDrawsResponse - 143, // 234: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftDrawSummary:output_type -> hyapp.activity.v1.GetLuckyGiftDrawSummaryResponse - 175, // [175:235] is the sub-list for method output_type - 115, // [115:175] is the sub-list for method input_type - 115, // [115:115] is the sub-list for extension type_name - 115, // [115:115] is the sub-list for extension extendee - 0, // [0:115] is the sub-list for field type_name + 128, // 101: hyapp.activity.v1.LuckyGiftRuleStage.tiers:type_name -> hyapp.activity.v1.LuckyGiftRuleTier + 129, // 102: hyapp.activity.v1.LuckyGiftRuleConfig.stages:type_name -> hyapp.activity.v1.LuckyGiftRuleStage + 0, // 103: hyapp.activity.v1.CheckLuckyGiftRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 125, // 104: hyapp.activity.v1.ExecuteLuckyGiftDrawRequest.lucky_gift:type_name -> hyapp.activity.v1.LuckyGiftMeta + 133, // 105: hyapp.activity.v1.ExecuteLuckyGiftDrawResponse.result:type_name -> hyapp.activity.v1.LuckyGiftDrawResult + 0, // 106: hyapp.activity.v1.GetLuckyGiftConfigRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 130, // 107: hyapp.activity.v1.GetLuckyGiftConfigResponse.config:type_name -> hyapp.activity.v1.LuckyGiftRuleConfig + 0, // 108: hyapp.activity.v1.UpsertLuckyGiftConfigRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 130, // 109: hyapp.activity.v1.UpsertLuckyGiftConfigRequest.config:type_name -> hyapp.activity.v1.LuckyGiftRuleConfig + 130, // 110: hyapp.activity.v1.UpsertLuckyGiftConfigResponse.config:type_name -> hyapp.activity.v1.LuckyGiftRuleConfig + 0, // 111: hyapp.activity.v1.ListLuckyGiftConfigsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 130, // 112: hyapp.activity.v1.ListLuckyGiftConfigsResponse.configs:type_name -> hyapp.activity.v1.LuckyGiftRuleConfig + 0, // 113: hyapp.activity.v1.ListLuckyGiftDrawsRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 133, // 114: hyapp.activity.v1.ListLuckyGiftDrawsResponse.draws:type_name -> hyapp.activity.v1.LuckyGiftDrawResult + 0, // 115: hyapp.activity.v1.GetLuckyGiftDrawSummaryRequest.meta:type_name -> hyapp.activity.v1.RequestMeta + 144, // 116: hyapp.activity.v1.GetLuckyGiftDrawSummaryResponse.summary:type_name -> hyapp.activity.v1.LuckyGiftDrawSummary + 1, // 117: hyapp.activity.v1.ActivityService.PingActivity:input_type -> hyapp.activity.v1.PingActivityRequest + 3, // 118: hyapp.activity.v1.ActivityService.GetActivityStatus:input_type -> hyapp.activity.v1.GetActivityStatusRequest + 6, // 119: hyapp.activity.v1.MessageInboxService.ListMessageTabs:input_type -> hyapp.activity.v1.ListMessageTabsRequest + 9, // 120: hyapp.activity.v1.MessageInboxService.ListInboxMessages:input_type -> hyapp.activity.v1.ListInboxMessagesRequest + 11, // 121: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:input_type -> hyapp.activity.v1.MarkInboxMessageReadRequest + 13, // 122: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:input_type -> hyapp.activity.v1.MarkInboxSectionReadRequest + 15, // 123: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:input_type -> hyapp.activity.v1.DeleteInboxMessageRequest + 17, // 124: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:input_type -> hyapp.activity.v1.CreateInboxMessageRequest + 19, // 125: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:input_type -> hyapp.activity.v1.CreateFanoutJobRequest + 21, // 126: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:input_type -> hyapp.activity.v1.CronBatchRequest + 21, // 127: hyapp.activity.v1.ActivityCronService.ProcessLevelRewardBatch:input_type -> hyapp.activity.v1.CronBatchRequest + 21, // 128: hyapp.activity.v1.ActivityCronService.ProcessAchievementRewardBatch:input_type -> hyapp.activity.v1.CronBatchRequest + 25, // 129: hyapp.activity.v1.TaskService.ListUserTasks:input_type -> hyapp.activity.v1.ListUserTasksRequest + 27, // 130: hyapp.activity.v1.TaskService.ClaimTaskReward:input_type -> hyapp.activity.v1.ClaimTaskRewardRequest + 29, // 131: hyapp.activity.v1.TaskService.ConsumeTaskEvent:input_type -> hyapp.activity.v1.ConsumeTaskEventRequest + 94, // 132: hyapp.activity.v1.GrowthLevelService.GetMyLevelOverview:input_type -> hyapp.activity.v1.GetMyLevelOverviewRequest + 96, // 133: hyapp.activity.v1.GrowthLevelService.GetLevelTrack:input_type -> hyapp.activity.v1.GetLevelTrackRequest + 99, // 134: hyapp.activity.v1.GrowthLevelService.ListLevelRewards:input_type -> hyapp.activity.v1.ListLevelRewardsRequest + 101, // 135: hyapp.activity.v1.GrowthLevelService.ConsumeLevelEvent:input_type -> hyapp.activity.v1.ConsumeLevelEventRequest + 114, // 136: hyapp.activity.v1.AchievementService.ListAchievements:input_type -> hyapp.activity.v1.ListAchievementsRequest + 116, // 137: hyapp.activity.v1.AchievementService.ConsumeAchievementEvent:input_type -> hyapp.activity.v1.ConsumeAchievementEventRequest + 119, // 138: hyapp.activity.v1.AchievementService.ListMyBadges:input_type -> hyapp.activity.v1.ListMyBadgesRequest + 121, // 139: hyapp.activity.v1.AchievementService.SetBadgeDisplay:input_type -> hyapp.activity.v1.SetBadgeDisplayRequest + 131, // 140: hyapp.activity.v1.LuckyGiftService.CheckLuckyGift:input_type -> hyapp.activity.v1.CheckLuckyGiftRequest + 134, // 141: hyapp.activity.v1.LuckyGiftService.ExecuteLuckyGiftDraw:input_type -> hyapp.activity.v1.ExecuteLuckyGiftDrawRequest + 32, // 142: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:input_type -> hyapp.activity.v1.EnsureBroadcastGroupsRequest + 34, // 143: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:input_type -> hyapp.activity.v1.PublishRegionBroadcastRequest + 35, // 144: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:input_type -> hyapp.activity.v1.PublishGlobalBroadcastRequest + 37, // 145: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:input_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberRequest + 21, // 146: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:input_type -> hyapp.activity.v1.CronBatchRequest + 40, // 147: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:input_type -> hyapp.activity.v1.ConsumeRoomEventRequest + 43, // 148: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:input_type -> hyapp.activity.v1.ListTaskDefinitionsRequest + 45, // 149: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:input_type -> hyapp.activity.v1.UpsertTaskDefinitionRequest + 47, // 150: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:input_type -> hyapp.activity.v1.SetTaskDefinitionStatusRequest + 52, // 151: hyapp.activity.v1.RegistrationRewardService.GetRegistrationRewardEligibility:input_type -> hyapp.activity.v1.GetRegistrationRewardEligibilityRequest + 54, // 152: hyapp.activity.v1.RegistrationRewardService.IssueRegistrationReward:input_type -> hyapp.activity.v1.IssueRegistrationRewardRequest + 56, // 153: hyapp.activity.v1.AdminRegistrationRewardService.GetRegistrationRewardConfig:input_type -> hyapp.activity.v1.GetRegistrationRewardConfigRequest + 58, // 154: hyapp.activity.v1.AdminRegistrationRewardService.UpdateRegistrationRewardConfig:input_type -> hyapp.activity.v1.UpdateRegistrationRewardConfigRequest + 60, // 155: hyapp.activity.v1.AdminRegistrationRewardService.ListRegistrationRewardClaims:input_type -> hyapp.activity.v1.ListRegistrationRewardClaimsRequest + 66, // 156: hyapp.activity.v1.FirstRechargeRewardService.GetFirstRechargeRewardStatus:input_type -> hyapp.activity.v1.GetFirstRechargeRewardStatusRequest + 68, // 157: hyapp.activity.v1.FirstRechargeRewardService.ConsumeFirstRechargeReward:input_type -> hyapp.activity.v1.ConsumeFirstRechargeRewardRequest + 70, // 158: hyapp.activity.v1.AdminFirstRechargeRewardService.GetFirstRechargeRewardConfig:input_type -> hyapp.activity.v1.GetFirstRechargeRewardConfigRequest + 72, // 159: hyapp.activity.v1.AdminFirstRechargeRewardService.UpdateFirstRechargeRewardConfig:input_type -> hyapp.activity.v1.UpdateFirstRechargeRewardConfigRequest + 74, // 160: hyapp.activity.v1.AdminFirstRechargeRewardService.ListFirstRechargeRewardClaims:input_type -> hyapp.activity.v1.ListFirstRechargeRewardClaimsRequest + 79, // 161: hyapp.activity.v1.SevenDayCheckInService.GetSevenDayCheckInStatus:input_type -> hyapp.activity.v1.GetSevenDayCheckInStatusRequest + 81, // 162: hyapp.activity.v1.SevenDayCheckInService.SignSevenDayCheckIn:input_type -> hyapp.activity.v1.SignSevenDayCheckInRequest + 83, // 163: hyapp.activity.v1.AdminSevenDayCheckInService.GetSevenDayCheckInConfig:input_type -> hyapp.activity.v1.GetSevenDayCheckInConfigRequest + 85, // 164: hyapp.activity.v1.AdminSevenDayCheckInService.UpdateSevenDayCheckInConfig:input_type -> hyapp.activity.v1.UpdateSevenDayCheckInConfigRequest + 88, // 165: hyapp.activity.v1.AdminSevenDayCheckInService.ListSevenDayCheckInClaims:input_type -> hyapp.activity.v1.ListSevenDayCheckInClaimsRequest + 109, // 166: hyapp.activity.v1.AdminGrowthLevelService.ListLevelConfig:input_type -> hyapp.activity.v1.ListLevelConfigRequest + 103, // 167: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTrack:input_type -> hyapp.activity.v1.UpsertLevelTrackRequest + 105, // 168: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelRule:input_type -> hyapp.activity.v1.UpsertLevelRuleRequest + 107, // 169: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTier:input_type -> hyapp.activity.v1.UpsertLevelTierRequest + 114, // 170: hyapp.activity.v1.AdminAchievementService.ListAchievementDefinitions:input_type -> hyapp.activity.v1.ListAchievementsRequest + 123, // 171: hyapp.activity.v1.AdminAchievementService.UpsertAchievementDefinition:input_type -> hyapp.activity.v1.UpsertAchievementDefinitionRequest + 136, // 172: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftConfig:input_type -> hyapp.activity.v1.GetLuckyGiftConfigRequest + 138, // 173: hyapp.activity.v1.AdminLuckyGiftService.UpsertLuckyGiftConfig:input_type -> hyapp.activity.v1.UpsertLuckyGiftConfigRequest + 140, // 174: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftConfigs:input_type -> hyapp.activity.v1.ListLuckyGiftConfigsRequest + 142, // 175: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftDraws:input_type -> hyapp.activity.v1.ListLuckyGiftDrawsRequest + 145, // 176: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftDrawSummary:input_type -> hyapp.activity.v1.GetLuckyGiftDrawSummaryRequest + 2, // 177: hyapp.activity.v1.ActivityService.PingActivity:output_type -> hyapp.activity.v1.PingActivityResponse + 4, // 178: hyapp.activity.v1.ActivityService.GetActivityStatus:output_type -> hyapp.activity.v1.GetActivityStatusResponse + 7, // 179: hyapp.activity.v1.MessageInboxService.ListMessageTabs:output_type -> hyapp.activity.v1.ListMessageTabsResponse + 10, // 180: hyapp.activity.v1.MessageInboxService.ListInboxMessages:output_type -> hyapp.activity.v1.ListInboxMessagesResponse + 12, // 181: hyapp.activity.v1.MessageInboxService.MarkInboxMessageRead:output_type -> hyapp.activity.v1.MarkInboxMessageReadResponse + 14, // 182: hyapp.activity.v1.MessageInboxService.MarkInboxSectionRead:output_type -> hyapp.activity.v1.MarkInboxSectionReadResponse + 16, // 183: hyapp.activity.v1.MessageInboxService.DeleteInboxMessage:output_type -> hyapp.activity.v1.DeleteInboxMessageResponse + 18, // 184: hyapp.activity.v1.MessageInboxService.CreateInboxMessage:output_type -> hyapp.activity.v1.CreateInboxMessageResponse + 20, // 185: hyapp.activity.v1.MessageInboxService.CreateFanoutJob:output_type -> hyapp.activity.v1.CreateFanoutJobResponse + 22, // 186: hyapp.activity.v1.ActivityCronService.ProcessMessageFanoutBatch:output_type -> hyapp.activity.v1.CronBatchResponse + 22, // 187: hyapp.activity.v1.ActivityCronService.ProcessLevelRewardBatch:output_type -> hyapp.activity.v1.CronBatchResponse + 22, // 188: hyapp.activity.v1.ActivityCronService.ProcessAchievementRewardBatch:output_type -> hyapp.activity.v1.CronBatchResponse + 26, // 189: hyapp.activity.v1.TaskService.ListUserTasks:output_type -> hyapp.activity.v1.ListUserTasksResponse + 28, // 190: hyapp.activity.v1.TaskService.ClaimTaskReward:output_type -> hyapp.activity.v1.ClaimTaskRewardResponse + 30, // 191: hyapp.activity.v1.TaskService.ConsumeTaskEvent:output_type -> hyapp.activity.v1.ConsumeTaskEventResponse + 95, // 192: hyapp.activity.v1.GrowthLevelService.GetMyLevelOverview:output_type -> hyapp.activity.v1.GetMyLevelOverviewResponse + 97, // 193: hyapp.activity.v1.GrowthLevelService.GetLevelTrack:output_type -> hyapp.activity.v1.GetLevelTrackResponse + 100, // 194: hyapp.activity.v1.GrowthLevelService.ListLevelRewards:output_type -> hyapp.activity.v1.ListLevelRewardsResponse + 102, // 195: hyapp.activity.v1.GrowthLevelService.ConsumeLevelEvent:output_type -> hyapp.activity.v1.ConsumeLevelEventResponse + 115, // 196: hyapp.activity.v1.AchievementService.ListAchievements:output_type -> hyapp.activity.v1.ListAchievementsResponse + 117, // 197: hyapp.activity.v1.AchievementService.ConsumeAchievementEvent:output_type -> hyapp.activity.v1.ConsumeAchievementEventResponse + 120, // 198: hyapp.activity.v1.AchievementService.ListMyBadges:output_type -> hyapp.activity.v1.ListMyBadgesResponse + 122, // 199: hyapp.activity.v1.AchievementService.SetBadgeDisplay:output_type -> hyapp.activity.v1.SetBadgeDisplayResponse + 132, // 200: hyapp.activity.v1.LuckyGiftService.CheckLuckyGift:output_type -> hyapp.activity.v1.CheckLuckyGiftResponse + 135, // 201: hyapp.activity.v1.LuckyGiftService.ExecuteLuckyGiftDraw:output_type -> hyapp.activity.v1.ExecuteLuckyGiftDrawResponse + 33, // 202: hyapp.activity.v1.BroadcastService.EnsureBroadcastGroups:output_type -> hyapp.activity.v1.EnsureBroadcastGroupsResponse + 36, // 203: hyapp.activity.v1.BroadcastService.PublishRegionBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse + 36, // 204: hyapp.activity.v1.BroadcastService.PublishGlobalBroadcast:output_type -> hyapp.activity.v1.PublishBroadcastResponse + 38, // 205: hyapp.activity.v1.BroadcastService.RemoveRegionBroadcastMember:output_type -> hyapp.activity.v1.RemoveRegionBroadcastMemberResponse + 39, // 206: hyapp.activity.v1.BroadcastService.ProcessBroadcastOutboxBatch:output_type -> hyapp.activity.v1.ProcessBroadcastOutboxBatchResponse + 41, // 207: hyapp.activity.v1.RoomEventConsumerService.ConsumeRoomEvent:output_type -> hyapp.activity.v1.ConsumeRoomEventResponse + 44, // 208: hyapp.activity.v1.AdminTaskService.ListTaskDefinitions:output_type -> hyapp.activity.v1.ListTaskDefinitionsResponse + 46, // 209: hyapp.activity.v1.AdminTaskService.UpsertTaskDefinition:output_type -> hyapp.activity.v1.UpsertTaskDefinitionResponse + 48, // 210: hyapp.activity.v1.AdminTaskService.SetTaskDefinitionStatus:output_type -> hyapp.activity.v1.SetTaskDefinitionStatusResponse + 53, // 211: hyapp.activity.v1.RegistrationRewardService.GetRegistrationRewardEligibility:output_type -> hyapp.activity.v1.GetRegistrationRewardEligibilityResponse + 55, // 212: hyapp.activity.v1.RegistrationRewardService.IssueRegistrationReward:output_type -> hyapp.activity.v1.IssueRegistrationRewardResponse + 57, // 213: hyapp.activity.v1.AdminRegistrationRewardService.GetRegistrationRewardConfig:output_type -> hyapp.activity.v1.GetRegistrationRewardConfigResponse + 59, // 214: hyapp.activity.v1.AdminRegistrationRewardService.UpdateRegistrationRewardConfig:output_type -> hyapp.activity.v1.UpdateRegistrationRewardConfigResponse + 61, // 215: hyapp.activity.v1.AdminRegistrationRewardService.ListRegistrationRewardClaims:output_type -> hyapp.activity.v1.ListRegistrationRewardClaimsResponse + 67, // 216: hyapp.activity.v1.FirstRechargeRewardService.GetFirstRechargeRewardStatus:output_type -> hyapp.activity.v1.GetFirstRechargeRewardStatusResponse + 69, // 217: hyapp.activity.v1.FirstRechargeRewardService.ConsumeFirstRechargeReward:output_type -> hyapp.activity.v1.ConsumeFirstRechargeRewardResponse + 71, // 218: hyapp.activity.v1.AdminFirstRechargeRewardService.GetFirstRechargeRewardConfig:output_type -> hyapp.activity.v1.GetFirstRechargeRewardConfigResponse + 73, // 219: hyapp.activity.v1.AdminFirstRechargeRewardService.UpdateFirstRechargeRewardConfig:output_type -> hyapp.activity.v1.UpdateFirstRechargeRewardConfigResponse + 75, // 220: hyapp.activity.v1.AdminFirstRechargeRewardService.ListFirstRechargeRewardClaims:output_type -> hyapp.activity.v1.ListFirstRechargeRewardClaimsResponse + 80, // 221: hyapp.activity.v1.SevenDayCheckInService.GetSevenDayCheckInStatus:output_type -> hyapp.activity.v1.GetSevenDayCheckInStatusResponse + 82, // 222: hyapp.activity.v1.SevenDayCheckInService.SignSevenDayCheckIn:output_type -> hyapp.activity.v1.SignSevenDayCheckInResponse + 84, // 223: hyapp.activity.v1.AdminSevenDayCheckInService.GetSevenDayCheckInConfig:output_type -> hyapp.activity.v1.GetSevenDayCheckInConfigResponse + 86, // 224: hyapp.activity.v1.AdminSevenDayCheckInService.UpdateSevenDayCheckInConfig:output_type -> hyapp.activity.v1.UpdateSevenDayCheckInConfigResponse + 89, // 225: hyapp.activity.v1.AdminSevenDayCheckInService.ListSevenDayCheckInClaims:output_type -> hyapp.activity.v1.ListSevenDayCheckInClaimsResponse + 110, // 226: hyapp.activity.v1.AdminGrowthLevelService.ListLevelConfig:output_type -> hyapp.activity.v1.ListLevelConfigResponse + 104, // 227: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTrack:output_type -> hyapp.activity.v1.UpsertLevelTrackResponse + 106, // 228: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelRule:output_type -> hyapp.activity.v1.UpsertLevelRuleResponse + 108, // 229: hyapp.activity.v1.AdminGrowthLevelService.UpsertLevelTier:output_type -> hyapp.activity.v1.UpsertLevelTierResponse + 115, // 230: hyapp.activity.v1.AdminAchievementService.ListAchievementDefinitions:output_type -> hyapp.activity.v1.ListAchievementsResponse + 124, // 231: hyapp.activity.v1.AdminAchievementService.UpsertAchievementDefinition:output_type -> hyapp.activity.v1.UpsertAchievementDefinitionResponse + 137, // 232: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftConfig:output_type -> hyapp.activity.v1.GetLuckyGiftConfigResponse + 139, // 233: hyapp.activity.v1.AdminLuckyGiftService.UpsertLuckyGiftConfig:output_type -> hyapp.activity.v1.UpsertLuckyGiftConfigResponse + 141, // 234: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftConfigs:output_type -> hyapp.activity.v1.ListLuckyGiftConfigsResponse + 143, // 235: hyapp.activity.v1.AdminLuckyGiftService.ListLuckyGiftDraws:output_type -> hyapp.activity.v1.ListLuckyGiftDrawsResponse + 146, // 236: hyapp.activity.v1.AdminLuckyGiftService.GetLuckyGiftDrawSummary:output_type -> hyapp.activity.v1.GetLuckyGiftDrawSummaryResponse + 177, // [177:237] is the sub-list for method output_type + 117, // [117:177] is the sub-list for method input_type + 117, // [117:117] is the sub-list for extension type_name + 117, // [117:117] is the sub-list for extension extendee + 0, // [0:117] is the sub-list for field type_name } func init() { file_proto_activity_v1_activity_proto_init() } @@ -13287,7 +13611,7 @@ func file_proto_activity_v1_activity_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_activity_v1_activity_proto_rawDesc), len(file_proto_activity_v1_activity_proto_rawDesc)), NumEnums: 0, - NumMessages: 144, + NumMessages: 147, NumExtensions: 0, NumServices: 19, }, diff --git a/api/proto/activity/v1/activity.proto b/api/proto/activity/v1/activity.proto index 40a3c751..a2f83613 100644 --- a/api/proto/activity/v1/activity.proto +++ b/api/proto/activity/v1/activity.proto @@ -1182,6 +1182,38 @@ message LuckyGiftConfig { repeated int64 multiplier_ppms = 40; } +message LuckyGiftRuleTier { + string stage = 1; + string tier_id = 2; + int64 multiplier_ppm = 3; + int64 base_weight_ppm = 4; + string reward_source = 5; + bool high_water_only = 6; + string broadcast_level = 7; + bool enabled = 8; +} + +message LuckyGiftRuleStage { + string stage = 1; + repeated LuckyGiftRuleTier tiers = 2; +} + +message LuckyGiftRuleConfig { + string app_code = 1; + string pool_id = 2; + int64 rule_version = 3; + bool enabled = 4; + int64 target_rtp_ppm = 5; + int64 pool_rate_ppm = 6; + int64 settlement_window_wager = 7; + int64 control_band_ppm = 8; + int64 gift_price_reference = 9; + int64 effective_from_ms = 10; + int64 created_by_admin_id = 11; + int64 created_at_ms = 12; + repeated LuckyGiftRuleStage stages = 13; +} + message CheckLuckyGiftRequest { RequestMeta meta = 1; int64 user_id = 2; @@ -1240,17 +1272,17 @@ message GetLuckyGiftConfigRequest { } message GetLuckyGiftConfigResponse { - LuckyGiftConfig config = 1; + LuckyGiftRuleConfig config = 1; } message UpsertLuckyGiftConfigRequest { RequestMeta meta = 1; - LuckyGiftConfig config = 2; + LuckyGiftRuleConfig config = 2; int64 operator_admin_id = 3; } message UpsertLuckyGiftConfigResponse { - LuckyGiftConfig config = 1; + LuckyGiftRuleConfig config = 1; } message ListLuckyGiftConfigsRequest { @@ -1258,7 +1290,7 @@ message ListLuckyGiftConfigsRequest { } message ListLuckyGiftConfigsResponse { - repeated LuckyGiftConfig configs = 1; + repeated LuckyGiftRuleConfig configs = 1; } message ListLuckyGiftDrawsRequest { diff --git a/server/admin/internal/modules/luckygift/handler.go b/server/admin/internal/modules/luckygift/handler.go index 58137b1c..b45bb4fe 100644 --- a/server/admin/internal/modules/luckygift/handler.go +++ b/server/admin/internal/modules/luckygift/handler.go @@ -1,6 +1,7 @@ package luckygift import ( + "math" "strings" "time" @@ -24,60 +25,38 @@ func New(activity activityclient.Client, audit shared.OperationLogger) *Handler } type configRequest struct { - PoolID string `json:"pool_id"` - Enabled bool `json:"enabled"` - GiftPrice int64 `json:"gift_price"` - TargetRTPPPM int64 `json:"target_rtp_ppm"` - PoolRatePPM int64 `json:"pool_rate_ppm"` - GlobalWindowDraws int64 `json:"global_window_draws"` - GiftWindowDraws int64 `json:"gift_window_draws"` - NoviceDrawLimit int64 `json:"novice_draw_limit"` - IntermediateDrawLimit int64 `json:"intermediate_draw_limit"` - HighMultiplier int64 `json:"high_multiplier"` - HighWaterPoolMultiple int64 `json:"high_water_pool_multiple"` - PlatformPoolWeightPPM int64 `json:"platform_pool_weight_ppm"` - RoomPoolWeightPPM int64 `json:"room_pool_weight_ppm"` - GiftPoolWeightPPM int64 `json:"gift_pool_weight_ppm"` - InitialPlatformPool int64 `json:"initial_platform_pool"` - InitialGiftPool int64 `json:"initial_gift_pool"` - InitialRoomPool int64 `json:"initial_room_pool"` - PlatformReserve int64 `json:"platform_reserve"` - GiftReserve int64 `json:"gift_reserve"` - RoomReserve int64 `json:"room_reserve"` - MaxSinglePayout int64 `json:"max_single_payout"` - UserHourlyPayoutCap int64 `json:"user_hourly_payout_cap"` - UserDailyPayoutCap int64 `json:"user_daily_payout_cap"` - DeviceDailyPayoutCap int64 `json:"device_daily_payout_cap"` - RoomHourlyPayoutCap int64 `json:"room_hourly_payout_cap"` - AnchorDailyPayoutCap int64 `json:"anchor_daily_payout_cap"` - RoomAtmosphereRatePPM int64 `json:"room_atmosphere_rate_ppm"` - RoomAtmosphereInitial int64 `json:"room_atmosphere_initial"` - RoomAtmosphereReserve int64 `json:"room_atmosphere_reserve"` - ActivityBudget int64 `json:"activity_budget"` - ActivityDailyLimit int64 `json:"activity_daily_limit"` - LargeTierEnabled bool `json:"large_tier_enabled"` - MultiplierPPMs []int64 `json:"multiplier_ppms"` - Tiers []tierDTO `json:"tiers"` + PoolID string `json:"pool_id"` + Enabled bool `json:"enabled"` + TargetRTPPercent float64 `json:"target_rtp_percent"` + PoolRatePercent float64 `json:"pool_rate_percent"` + SettlementWindowWager int64 `json:"settlement_window_wager"` + ControlBandPercent float64 `json:"control_band_percent"` + GiftPriceReference int64 `json:"gift_price_reference"` + EffectiveFromMS int64 `json:"effective_from_ms"` + Stages []stageDTO `json:"stages"` } type configDTO struct { configRequest AppCode string `json:"app_code"` - GiftID string `json:"gift_id"` RuleVersion int64 `json:"rule_version"` - UpdatedByAdminID int64 `json:"updated_by_admin_id"` + CreatedByAdminID int64 `json:"created_by_admin_id"` CreatedAtMS int64 `json:"created_at_ms"` - UpdatedAtMS int64 `json:"updated_at_ms"` +} + +type stageDTO struct { + Stage string `json:"stage"` + Tiers []tierDTO `json:"tiers"` } type tierDTO struct { - Pool string `json:"pool"` - TierID string `json:"tier_id"` - RewardCoins int64 `json:"reward_coins"` - MultiplierPPM int64 `json:"multiplier_ppm"` - Weight int64 `json:"weight"` - HighWaterOnly bool `json:"high_water_only"` - Enabled bool `json:"enabled"` + TierID string `json:"tier_id"` + Multiplier float64 `json:"multiplier"` + ProbabilityPercent float64 `json:"probability_percent"` + RewardSource string `json:"reward_source"` + HighWaterOnly bool `json:"high_water_only"` + BroadcastLevel string `json:"broadcast_level"` + Enabled bool `json:"enabled"` } type drawDTO struct { @@ -218,123 +197,99 @@ func (h *Handler) meta(c *gin.Context) *activityv1.RequestMeta { } } -func configToProto(req configRequest) *activityv1.LuckyGiftConfig { - tiers := make([]*activityv1.LuckyGiftTier, 0, len(req.Tiers)) - for _, tier := range req.Tiers { - tiers = append(tiers, &activityv1.LuckyGiftTier{ - Pool: tier.Pool, - TierId: tier.TierID, - RewardCoins: tier.RewardCoins, - MultiplierPpm: tier.MultiplierPPM, - Weight: tier.Weight, - HighWaterOnly: tier.HighWaterOnly, - Enabled: tier.Enabled, +func configToProto(req configRequest) *activityv1.LuckyGiftRuleConfig { + stages := make([]*activityv1.LuckyGiftRuleStage, 0, len(req.Stages)) + for _, stage := range req.Stages { + tiers := make([]*activityv1.LuckyGiftRuleTier, 0, len(stage.Tiers)) + for _, tier := range stage.Tiers { + tiers = append(tiers, &activityv1.LuckyGiftRuleTier{ + Stage: strings.TrimSpace(stage.Stage), + TierId: strings.TrimSpace(tier.TierID), + MultiplierPpm: multiplierToPPM(tier.Multiplier), + BaseWeightPpm: percentToPPM(tier.ProbabilityPercent), + RewardSource: strings.TrimSpace(tier.RewardSource), + HighWaterOnly: tier.HighWaterOnly, + BroadcastLevel: strings.TrimSpace(tier.BroadcastLevel), + Enabled: tier.Enabled, + }) + } + stages = append(stages, &activityv1.LuckyGiftRuleStage{ + Stage: strings.TrimSpace(stage.Stage), + Tiers: tiers, }) } - return &activityv1.LuckyGiftConfig{ + return &activityv1.LuckyGiftRuleConfig{ PoolId: strings.TrimSpace(req.PoolID), Enabled: req.Enabled, - GiftPrice: req.GiftPrice, - TargetRtpPpm: req.TargetRTPPPM, - PoolRatePpm: req.PoolRatePPM, - GlobalWindowDraws: req.GlobalWindowDraws, - GiftWindowDraws: req.GiftWindowDraws, - NoviceDrawLimit: req.NoviceDrawLimit, - IntermediateDrawLimit: req.IntermediateDrawLimit, - HighMultiplier: req.HighMultiplier, - HighWaterPoolMultiple: req.HighWaterPoolMultiple, - PlatformPoolWeightPpm: req.PlatformPoolWeightPPM, - RoomPoolWeightPpm: req.RoomPoolWeightPPM, - GiftPoolWeightPpm: req.GiftPoolWeightPPM, - InitialPlatformPool: req.InitialPlatformPool, - InitialGiftPool: req.InitialGiftPool, - InitialRoomPool: req.InitialRoomPool, - PlatformReserve: req.PlatformReserve, - GiftReserve: req.GiftReserve, - RoomReserve: req.RoomReserve, - MaxSinglePayout: req.MaxSinglePayout, - UserHourlyPayoutCap: req.UserHourlyPayoutCap, - UserDailyPayoutCap: req.UserDailyPayoutCap, - DeviceDailyPayoutCap: req.DeviceDailyPayoutCap, - RoomHourlyPayoutCap: req.RoomHourlyPayoutCap, - AnchorDailyPayoutCap: req.AnchorDailyPayoutCap, - RoomAtmosphereRatePpm: req.RoomAtmosphereRatePPM, - RoomAtmosphereInitial: req.RoomAtmosphereInitial, - RoomAtmosphereReserve: req.RoomAtmosphereReserve, - ActivityBudget: req.ActivityBudget, - ActivityDailyLimit: req.ActivityDailyLimit, - LargeTierEnabled: req.LargeTierEnabled, - MultiplierPpms: append([]int64(nil), req.MultiplierPPMs...), - Tiers: tiers, + TargetRtpPpm: percentToPPM(req.TargetRTPPercent), + PoolRatePpm: percentToPPM(req.PoolRatePercent), + SettlementWindowWager: req.SettlementWindowWager, + ControlBandPpm: percentToPPM(req.ControlBandPercent), + GiftPriceReference: req.GiftPriceReference, + EffectiveFromMs: req.EffectiveFromMS, + Stages: stages, } } -func configFromProto(config *activityv1.LuckyGiftConfig) configDTO { +func configFromProto(config *activityv1.LuckyGiftRuleConfig) configDTO { if config == nil { return configDTO{} } - tiers := make([]tierDTO, 0, len(config.GetTiers())) - for _, tier := range config.GetTiers() { - tiers = append(tiers, tierDTO{ - Pool: tier.GetPool(), - TierID: tier.GetTierId(), - RewardCoins: tier.GetRewardCoins(), - MultiplierPPM: tier.GetMultiplierPpm(), - Weight: tier.GetWeight(), - HighWaterOnly: tier.GetHighWaterOnly(), - Enabled: tier.GetEnabled(), + stages := make([]stageDTO, 0, len(config.GetStages())) + for _, stage := range config.GetStages() { + tiers := make([]tierDTO, 0, len(stage.GetTiers())) + for _, tier := range stage.GetTiers() { + tiers = append(tiers, tierDTO{ + TierID: tier.GetTierId(), + Multiplier: ppmToMultiplier(tier.GetMultiplierPpm()), + ProbabilityPercent: ppmToPercent(tier.GetBaseWeightPpm()), + RewardSource: tier.GetRewardSource(), + HighWaterOnly: tier.GetHighWaterOnly(), + BroadcastLevel: tier.GetBroadcastLevel(), + Enabled: tier.GetEnabled(), + }) + } + stages = append(stages, stageDTO{ + Stage: stage.GetStage(), + Tiers: tiers, }) } poolID := strings.TrimSpace(config.GetPoolId()) - if poolID == "" { - poolID = strings.TrimSpace(config.GetGiftId()) - } return configDTO{ AppCode: config.GetAppCode(), - GiftID: config.GetGiftId(), RuleVersion: config.GetRuleVersion(), - UpdatedByAdminID: config.GetUpdatedByAdminId(), + CreatedByAdminID: config.GetCreatedByAdminId(), CreatedAtMS: config.GetCreatedAtMs(), - UpdatedAtMS: config.GetUpdatedAtMs(), configRequest: configRequest{ PoolID: poolID, Enabled: config.GetEnabled(), - GiftPrice: config.GetGiftPrice(), - TargetRTPPPM: config.GetTargetRtpPpm(), - PoolRatePPM: config.GetPoolRatePpm(), - GlobalWindowDraws: config.GetGlobalWindowDraws(), - GiftWindowDraws: config.GetGiftWindowDraws(), - NoviceDrawLimit: config.GetNoviceDrawLimit(), - IntermediateDrawLimit: config.GetIntermediateDrawLimit(), - HighMultiplier: config.GetHighMultiplier(), - HighWaterPoolMultiple: config.GetHighWaterPoolMultiple(), - PlatformPoolWeightPPM: config.GetPlatformPoolWeightPpm(), - RoomPoolWeightPPM: config.GetRoomPoolWeightPpm(), - GiftPoolWeightPPM: config.GetGiftPoolWeightPpm(), - InitialPlatformPool: config.GetInitialPlatformPool(), - InitialGiftPool: config.GetInitialGiftPool(), - InitialRoomPool: config.GetInitialRoomPool(), - PlatformReserve: config.GetPlatformReserve(), - GiftReserve: config.GetGiftReserve(), - RoomReserve: config.GetRoomReserve(), - MaxSinglePayout: config.GetMaxSinglePayout(), - UserHourlyPayoutCap: config.GetUserHourlyPayoutCap(), - UserDailyPayoutCap: config.GetUserDailyPayoutCap(), - DeviceDailyPayoutCap: config.GetDeviceDailyPayoutCap(), - RoomHourlyPayoutCap: config.GetRoomHourlyPayoutCap(), - AnchorDailyPayoutCap: config.GetAnchorDailyPayoutCap(), - RoomAtmosphereRatePPM: config.GetRoomAtmosphereRatePpm(), - RoomAtmosphereInitial: config.GetRoomAtmosphereInitial(), - RoomAtmosphereReserve: config.GetRoomAtmosphereReserve(), - ActivityBudget: config.GetActivityBudget(), - ActivityDailyLimit: config.GetActivityDailyLimit(), - LargeTierEnabled: config.GetLargeTierEnabled(), - MultiplierPPMs: append([]int64(nil), config.GetMultiplierPpms()...), - Tiers: tiers, + TargetRTPPercent: ppmToPercent(config.GetTargetRtpPpm()), + PoolRatePercent: ppmToPercent(config.GetPoolRatePpm()), + SettlementWindowWager: config.GetSettlementWindowWager(), + ControlBandPercent: ppmToPercent(config.GetControlBandPpm()), + GiftPriceReference: config.GetGiftPriceReference(), + EffectiveFromMS: config.GetEffectiveFromMs(), + Stages: stages, }, } } +func percentToPPM(value float64) int64 { + return int64(math.Round(value * 10_000)) +} + +func ppmToPercent(value int64) float64 { + return float64(value) / 10_000 +} + +func multiplierToPPM(value float64) int64 { + return int64(math.Round(value * 1_000_000)) +} + +func ppmToMultiplier(value int64) float64 { + return float64(value) / 1_000_000 +} + func drawFromProto(draw *activityv1.LuckyGiftDrawResult) drawDTO { if draw == nil { return drawDTO{} diff --git a/server/admin/internal/modules/luckygift/handler_test.go b/server/admin/internal/modules/luckygift/handler_test.go new file mode 100644 index 00000000..b6f26e96 --- /dev/null +++ b/server/admin/internal/modules/luckygift/handler_test.go @@ -0,0 +1,107 @@ +package luckygift + +import ( + "testing" + + activityv1 "hyapp.local/api/proto/activity/v1" +) + +func TestConfigToProtoConvertsBusinessUnitsToPPM(t *testing.T) { + config := configToProto(configRequest{ + PoolID: " lucky_100 ", + Enabled: true, + TargetRTPPercent: 95, + PoolRatePercent: 96, + SettlementWindowWager: 1_000_000, + ControlBandPercent: 1, + GiftPriceReference: 100, + Stages: []stageDTO{ + { + Stage: " novice ", + Tiers: []tierDTO{ + { + TierID: " novice_0_3x ", + Multiplier: 0.3, + ProbabilityPercent: 22, + RewardSource: " base_rtp ", + BroadcastLevel: " room ", + Enabled: true, + }, + }, + }, + }, + }) + + if config.GetPoolId() != "lucky_100" { + t.Fatalf("pool id = %q, want lucky_100", config.GetPoolId()) + } + if config.GetTargetRtpPpm() != 950_000 { + t.Fatalf("target rtp ppm = %d, want 950000", config.GetTargetRtpPpm()) + } + if config.GetPoolRatePpm() != 960_000 { + t.Fatalf("pool rate ppm = %d, want 960000", config.GetPoolRatePpm()) + } + if config.GetControlBandPpm() != 10_000 { + t.Fatalf("control band ppm = %d, want 10000", config.GetControlBandPpm()) + } + tier := config.GetStages()[0].GetTiers()[0] + if tier.GetStage() != "novice" { + t.Fatalf("tier stage = %q, want novice", tier.GetStage()) + } + if tier.GetTierId() != "novice_0_3x" { + t.Fatalf("tier id = %q, want novice_0_3x", tier.GetTierId()) + } + if tier.GetMultiplierPpm() != 300_000 { + t.Fatalf("multiplier ppm = %d, want 300000", tier.GetMultiplierPpm()) + } + if tier.GetBaseWeightPpm() != 220_000 { + t.Fatalf("base weight ppm = %d, want 220000", tier.GetBaseWeightPpm()) + } +} + +func TestConfigFromProtoConvertsPPMToBusinessUnits(t *testing.T) { + config := configFromProto(&activityv1.LuckyGiftRuleConfig{ + AppCode: "hyapp", + PoolId: "lucky_100", + RuleVersion: 7, + Enabled: true, + TargetRtpPpm: 950_000, + PoolRatePpm: 960_000, + SettlementWindowWager: 1_000_000, + ControlBandPpm: 10_000, + GiftPriceReference: 100, + CreatedByAdminId: 12, + CreatedAtMs: 1_700_000_000_000, + Stages: []*activityv1.LuckyGiftRuleStage{ + { + Stage: "novice", + Tiers: []*activityv1.LuckyGiftRuleTier{ + { + TierId: "novice_0_3x", + MultiplierPpm: 300_000, + BaseWeightPpm: 220_000, + RewardSource: "base_rtp", + BroadcastLevel: "room", + Enabled: true, + }, + }, + }, + }, + }) + + if config.TargetRTPPercent != 95 { + t.Fatalf("target rtp percent = %v, want 95", config.TargetRTPPercent) + } + if config.PoolRatePercent != 96 { + t.Fatalf("pool rate percent = %v, want 96", config.PoolRatePercent) + } + if config.ControlBandPercent != 1 { + t.Fatalf("control band percent = %v, want 1", config.ControlBandPercent) + } + if config.Stages[0].Tiers[0].Multiplier != 0.3 { + t.Fatalf("multiplier = %v, want 0.3", config.Stages[0].Tiers[0].Multiplier) + } + if config.Stages[0].Tiers[0].ProbabilityPercent != 22 { + t.Fatalf("probability percent = %v, want 22", config.Stages[0].Tiers[0].ProbabilityPercent) + } +} diff --git a/services/activity-service/deploy/mysql/initdb/001_activity_service.sql b/services/activity-service/deploy/mysql/initdb/001_activity_service.sql index cabed0d0..7f234a92 100644 --- a/services/activity-service/deploy/mysql/initdb/001_activity_service.sql +++ b/services/activity-service/deploy/mysql/initdb/001_activity_service.sql @@ -90,6 +90,40 @@ CREATE TABLE IF NOT EXISTS lucky_gift_rules ( KEY idx_lucky_gift_rules_enabled (app_code, enabled, updated_at_ms) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物规则表'; +CREATE TABLE IF NOT EXISTS lucky_gift_rule_versions ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码', + pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID', + rule_version BIGINT NOT NULL COMMENT '不可变规则版本', + enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否启用', + target_rtp_ppm BIGINT NOT NULL COMMENT '基础返奖目标,ppm', + pool_rate_ppm BIGINT NOT NULL COMMENT '每笔扣费进入基础奖池比例,ppm', + settlement_window_wager BIGINT NOT NULL COMMENT 'RTP 结算窗口流水,单位金币', + control_band_ppm BIGINT NOT NULL COMMENT '正常波动带,ppm', + gift_price_reference BIGINT NOT NULL COMMENT '配置参考礼物价格', + effective_from_ms BIGINT NOT NULL COMMENT '生效时间,UTC epoch ms', + created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '发布人', + created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', + PRIMARY KEY (app_code, pool_id, rule_version), + KEY idx_lucky_gift_rule_versions_latest (app_code, pool_id, rule_version), + KEY idx_lucky_gift_rule_versions_enabled (app_code, enabled, created_at_ms) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 v2 规则版本表'; + +CREATE TABLE IF NOT EXISTS lucky_gift_stage_tiers ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码', + pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID', + rule_version BIGINT NOT NULL COMMENT '规则版本', + stage VARCHAR(32) NOT NULL COMMENT 'novice/normal/advanced', + tier_id VARCHAR(96) NOT NULL COMMENT '奖档 ID', + multiplier_ppm BIGINT NOT NULL COMMENT '倍率,1x = 1000000', + base_weight_ppm BIGINT NOT NULL COMMENT '正常模式基础概率,ppm', + reward_source VARCHAR(32) NOT NULL COMMENT 'base_rtp/activity_subsidy/presentation_only', + high_water_only TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否高水位才开放', + broadcast_level VARCHAR(32) NOT NULL DEFAULT 'none' COMMENT 'none/room/region/global', + enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用', + PRIMARY KEY (app_code, pool_id, rule_version, stage, tier_id), + KEY idx_lucky_gift_stage_tiers_stage (app_code, pool_id, rule_version, stage) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 v2 阶段奖档表'; + CREATE TABLE IF NOT EXISTS lucky_rtp_windows ( app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码', scope_type VARCHAR(32) NOT NULL COMMENT 'global 或 gift', diff --git a/services/activity-service/internal/domain/luckygift/lucky_gift.go b/services/activity-service/internal/domain/luckygift/lucky_gift.go index 6c1272b6..2d96c23c 100644 --- a/services/activity-service/internal/domain/luckygift/lucky_gift.go +++ b/services/activity-service/internal/domain/luckygift/lucky_gift.go @@ -15,10 +15,19 @@ const ( PoolIntermediate = "intermediate" PoolAdvanced = "advanced" + StageNovice = "novice" + StageNormal = "normal" + StageAdvanced = "advanced" + SourceBaseRTP = "base_rtp" SourceRoomAtmosphere = "room_atmosphere" SourceActivity = "activity_subsidy" SourcePresentation = "presentation_only" + + BroadcastNone = "none" + BroadcastRoom = "room" + BroadcastRegion = "region" + BroadcastGlobal = "global" ) // Tier 是单个体验池里的候选奖档;权重只塑造体验节奏,基础成本仍由 RTP 窗口兜住。 @@ -76,6 +85,41 @@ type Config struct { UpdatedAtMS int64 `json:"updated_at_ms"` } +// RuleTier 是 v2 配置契约里的阶段奖档。倍率和概率在服务端内部统一用 ppm 保存。 +type RuleTier struct { + Stage string `json:"stage"` + TierID string `json:"tier_id"` + MultiplierPPM int64 `json:"multiplier_ppm"` + BaseWeightPPM int64 `json:"base_weight_ppm"` + RewardSource string `json:"reward_source"` + HighWaterOnly bool `json:"high_water_only"` + BroadcastLevel string `json:"broadcast_level"` + Enabled bool `json:"enabled"` +} + +// RuleStage 保存某个用户阶段的完整奖档概率。每个阶段的基础概率必须合计 1000000。 +type RuleStage struct { + Stage string `json:"stage"` + Tiers []RuleTier `json:"tiers"` +} + +// RuleConfig 是幸运礼物 v2 配置版本快照。比例和倍率均为 ppm,业务单位转换发生在发布入口。 +type RuleConfig struct { + AppCode string `json:"app_code"` + PoolID string `json:"pool_id"` + RuleVersion int64 `json:"rule_version"` + Enabled bool `json:"enabled"` + TargetRTPPPM int64 `json:"target_rtp_ppm"` + PoolRatePPM int64 `json:"pool_rate_ppm"` + SettlementWindowWager int64 `json:"settlement_window_wager"` + ControlBandPPM int64 `json:"control_band_ppm"` + GiftPriceReference int64 `json:"gift_price_reference"` + EffectiveFromMS int64 `json:"effective_from_ms"` + CreatedByAdminID int64 `json:"created_by_admin_id"` + CreatedAtMS int64 `json:"created_at_ms"` + Stages []RuleStage `json:"stages"` +} + type CheckCommand struct { PoolID string GiftID string diff --git a/services/activity-service/internal/service/luckygift/config.go b/services/activity-service/internal/service/luckygift/config.go index f48b437e..82afff96 100644 --- a/services/activity-service/internal/service/luckygift/config.go +++ b/services/activity-service/internal/service/luckygift/config.go @@ -9,7 +9,10 @@ import ( domain "hyapp/services/activity-service/internal/domain/luckygift" ) -const ppmScale int64 = 1_000_000 +const ( + ppmScale int64 = 1_000_000 + highTierMultiplierPPM int64 = 10_000_000 +) // DefaultConfig 给后台指定奖池提供规则草稿;真正生效必须由后台显式 enabled。 func DefaultConfig(appCode, poolID string) domain.Config { @@ -55,6 +58,191 @@ func DefaultConfig(appCode, poolID string) domain.Config { } } +// DefaultRuleConfig 返回 v2 配置草稿。草稿默认 disabled,只有后台发布后才写入不可变版本表。 +func DefaultRuleConfig(appCode, poolID string) domain.RuleConfig { + poolID = normalizePoolID(poolID) + return domain.RuleConfig{ + AppCode: appCode, + PoolID: poolID, + Enabled: false, + TargetRTPPPM: 950_000, + PoolRatePPM: 960_000, + SettlementWindowWager: 1_000_000, + ControlBandPPM: 10_000, + GiftPriceReference: 100, + Stages: []domain.RuleStage{ + defaultRuleStage(domain.StageNovice, []ruleTierSeed{ + {id: "novice_none", multiplierPPM: 0, weightPPM: 300_000}, + {id: "novice_0_3x", multiplierPPM: 300_000, weightPPM: 220_000}, + {id: "novice_0_5x", multiplierPPM: 500_000, weightPPM: 180_000}, + {id: "novice_1x", multiplierPPM: 1_000_000, weightPPM: 300_000}, + }), + defaultRuleStage(domain.StageNormal, []ruleTierSeed{ + {id: "normal_none", multiplierPPM: 0, weightPPM: 400_000}, + {id: "normal_0_5x", multiplierPPM: 500_000, weightPPM: 250_000}, + {id: "normal_1x", multiplierPPM: 1_000_000, weightPPM: 250_000}, + {id: "normal_2x", multiplierPPM: 2_000_000, weightPPM: 100_000}, + }), + defaultRuleStage(domain.StageAdvanced, []ruleTierSeed{ + {id: "advanced_none", multiplierPPM: 0, weightPPM: 500_000}, + {id: "advanced_1x", multiplierPPM: 1_000_000, weightPPM: 300_000}, + {id: "advanced_2x", multiplierPPM: 2_000_000, weightPPM: 150_000}, + {id: "advanced_5x", multiplierPPM: 5_000_000, weightPPM: 50_000}, + }), + }, + } +} + +type ruleTierSeed struct { + id string + multiplierPPM int64 + weightPPM int64 +} + +func defaultRuleStage(stage string, tiers []ruleTierSeed) domain.RuleStage { + out := domain.RuleStage{Stage: stage, Tiers: make([]domain.RuleTier, 0, len(tiers))} + for _, tier := range tiers { + out.Tiers = append(out.Tiers, domain.RuleTier{ + Stage: stage, + TierID: tier.id, + MultiplierPPM: tier.multiplierPPM, + BaseWeightPPM: tier.weightPPM, + RewardSource: domain.SourceBaseRTP, + HighWaterOnly: tier.multiplierPPM >= highTierMultiplierPPM, + BroadcastLevel: domain.BroadcastNone, + Enabled: true, + }) + } + return out +} + +func normalizeRuleConfig(config domain.RuleConfig) domain.RuleConfig { + config.PoolID = normalizePoolID(config.PoolID) + for stageIndex, stage := range config.Stages { + stage.Stage = strings.TrimSpace(stage.Stage) + for tierIndex, tier := range stage.Tiers { + tier.Stage = strings.TrimSpace(tier.Stage) + if tier.Stage == "" { + tier.Stage = stage.Stage + } + tier.TierID = strings.TrimSpace(tier.TierID) + tier.RewardSource = strings.TrimSpace(tier.RewardSource) + if tier.RewardSource == "" { + tier.RewardSource = domain.SourceBaseRTP + } + tier.BroadcastLevel = strings.TrimSpace(tier.BroadcastLevel) + if tier.BroadcastLevel == "" { + tier.BroadcastLevel = domain.BroadcastNone + } + stage.Tiers[tierIndex] = tier + } + config.Stages[stageIndex] = stage + } + return config +} + +func validateRuleConfig(config domain.RuleConfig) error { + if normalizePoolID(config.PoolID) == "" { + return xerr.New(xerr.InvalidArgument, "lucky gift pool id is required") + } + if config.TargetRTPPPM < 100_000 || config.TargetRTPPPM > 990_000 { + return xerr.New(xerr.InvalidArgument, "target RTP must be between 10% and 99%") + } + if config.PoolRatePPM < config.TargetRTPPPM || config.PoolRatePPM > ppmScale { + return xerr.New(xerr.InvalidArgument, "pool rate must be between target RTP and 100%") + } + if config.SettlementWindowWager <= 0 { + return xerr.New(xerr.InvalidArgument, "settlement window wager must be positive") + } + if config.ControlBandPPM <= 0 || config.ControlBandPPM > 50_000 { + return xerr.New(xerr.InvalidArgument, "control band must be greater than 0 and no more than 5%") + } + if config.GiftPriceReference <= 0 { + return xerr.New(xerr.InvalidArgument, "gift price reference must be positive") + } + stageMap := make(map[string]domain.RuleStage, len(config.Stages)) + for _, stage := range config.Stages { + if !validRuleStage(stage.Stage) { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("invalid lucky gift stage: %s", stage.Stage)) + } + if _, exists := stageMap[stage.Stage]; exists { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("duplicate lucky gift stage: %s", stage.Stage)) + } + stageMap[stage.Stage] = stage + } + for _, stageName := range []string{domain.StageNovice, domain.StageNormal, domain.StageAdvanced} { + stage, exists := stageMap[stageName] + if !exists { + return xerr.New(xerr.InvalidArgument, "lucky gift stages must include novice, normal and advanced") + } + if err := validateRuleStage(stage); err != nil { + return err + } + } + return nil +} + +func validateRuleStage(stage domain.RuleStage) error { + var weightSum int64 + hasBaseTier := false + hasZeroTier := false + for _, tier := range stage.Tiers { + if tier.Stage != stage.Stage { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("tier %s stage does not match %s", tier.TierID, stage.Stage)) + } + if tier.TierID == "" { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s tier id is required", stage.Stage)) + } + if tier.MultiplierPPM < 0 { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s tier multiplier is invalid", tier.TierID)) + } + if tier.BaseWeightPPM < 0 { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s tier probability is invalid", tier.TierID)) + } + if !validRewardSource(tier.RewardSource) { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s reward source is invalid", tier.TierID)) + } + if !validBroadcastLevel(tier.BroadcastLevel) { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s broadcast level is invalid", tier.TierID)) + } + if tier.Enabled { + weightSum += tier.BaseWeightPPM + hasBaseTier = hasBaseTier || tier.RewardSource == domain.SourceBaseRTP + hasZeroTier = hasZeroTier || tier.MultiplierPPM == 0 + } + if tier.Enabled && tier.MultiplierPPM >= highTierMultiplierPPM && !tier.HighWaterOnly { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s high multiplier tier must be high-water only", tier.TierID)) + } + } + if weightSum != ppmScale { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s stage probability must sum to 100%%", stage.Stage)) + } + if !hasBaseTier { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s stage must include at least one base RTP tier", stage.Stage)) + } + if !hasZeroTier { + return xerr.New(xerr.InvalidArgument, fmt.Sprintf("%s stage must include explicit 0x tier", stage.Stage)) + } + return nil +} + +func validRuleStage(stage string) bool { + return stage == domain.StageNovice || stage == domain.StageNormal || stage == domain.StageAdvanced +} + +func validRewardSource(source string) bool { + return source == domain.SourceBaseRTP || + source == domain.SourceActivity || + source == domain.SourcePresentation +} + +func validBroadcastLevel(level string) bool { + return level == domain.BroadcastNone || + level == domain.BroadcastRoom || + level == domain.BroadcastRegion || + level == domain.BroadcastGlobal +} + // validateConfig 只校验会破坏线上抽奖不变量的字段;展示类默认值留给后台表单处理。 func validateConfig(config domain.Config) error { if normalizePoolID(config.PoolID) == "" { diff --git a/services/activity-service/internal/service/luckygift/config_test.go b/services/activity-service/internal/service/luckygift/config_test.go index c7deb170..02ebf86c 100644 --- a/services/activity-service/internal/service/luckygift/config_test.go +++ b/services/activity-service/internal/service/luckygift/config_test.go @@ -63,3 +63,39 @@ func TestValidateConfigRejectsMultiplierListBelowTargetRTP(t *testing.T) { t.Fatalf("expected max multiplier below RTP to be rejected") } } + +func TestDefaultRuleConfigPassesValidation(t *testing.T) { + config := DefaultRuleConfig("hyapp", "pool_v2") + config.Enabled = true + + if err := validateRuleConfig(config); err != nil { + t.Fatalf("default v2 lucky gift config should be publishable: %v", err) + } +} + +func TestValidateRuleConfigRejectsPercentSubmittedAsPPM(t *testing.T) { + config := DefaultRuleConfig("hyapp", "pool_bad_rtp") + config.TargetRTPPPM = 95 + + if err := validateRuleConfig(config); err == nil { + t.Fatalf("expected raw percent value in ppm field to be rejected") + } +} + +func TestValidateRuleConfigRejectsStageWeightMismatch(t *testing.T) { + config := DefaultRuleConfig("hyapp", "pool_bad_weight") + config.Stages[0].Tiers[0].BaseWeightPPM = 299_999 + + if err := validateRuleConfig(config); err == nil { + t.Fatalf("expected stage probability sum mismatch to be rejected") + } +} + +func TestValidateRuleConfigRequiresExplicitZeroTier(t *testing.T) { + config := DefaultRuleConfig("hyapp", "pool_no_zero") + config.Stages[1].Tiers = config.Stages[1].Tiers[1:] + + if err := validateRuleConfig(config); err == nil { + t.Fatalf("expected stage without 0x tier to be rejected") + } +} diff --git a/services/activity-service/internal/service/luckygift/service.go b/services/activity-service/internal/service/luckygift/service.go index 4276b7fd..7c6ab3bd 100644 --- a/services/activity-service/internal/service/luckygift/service.go +++ b/services/activity-service/internal/service/luckygift/service.go @@ -21,9 +21,9 @@ import ( // Repository 是幸运礼物唯一持久化边界;RTP、奖池、风控计数必须在同一个 MySQL 事务内修改。 type Repository interface { - GetLuckyGiftConfig(ctx context.Context, poolID string) (domain.Config, bool, error) - UpsertLuckyGiftConfig(ctx context.Context, config domain.Config, nowMS int64) (domain.Config, error) - ListLuckyGiftConfigs(ctx context.Context) ([]domain.Config, error) + GetLuckyGiftRuleConfig(ctx context.Context, poolID string) (domain.RuleConfig, bool, error) + PublishLuckyGiftRuleConfig(ctx context.Context, config domain.RuleConfig, nowMS int64) (domain.RuleConfig, error) + ListLuckyGiftRuleConfigs(ctx context.Context) ([]domain.RuleConfig, error) CheckLuckyGift(ctx context.Context, cmd domain.CheckCommand) (domain.CheckResult, error) ExecuteLuckyGiftDraw(ctx context.Context, cmd domain.DrawCommand, nowMS int64) (domain.DrawResult, error) ListLuckyGiftDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error) @@ -285,43 +285,40 @@ func (s *Service) markOutboxFailed(ctx context.Context, event domain.DrawOutbox, return s.repository.MarkLuckyGiftOutboxRetryable(ctx, event, nextRetryCount, nextRetryAtMS, cause.Error(), nowMS) } -func (s *Service) GetConfig(ctx context.Context, poolID string) (domain.Config, error) { +func (s *Service) GetConfig(ctx context.Context, poolID string) (domain.RuleConfig, error) { if err := s.requireRepository(); err != nil { - return domain.Config{}, err + return domain.RuleConfig{}, err } poolID = normalizePoolID(poolID) - config, exists, err := s.repository.GetLuckyGiftConfig(ctx, poolID) + config, exists, err := s.repository.GetLuckyGiftRuleConfig(ctx, poolID) if err != nil { - return domain.Config{}, err + return domain.RuleConfig{}, err } if !exists { - // 未配置时返回 disabled 草稿,后台可以直接编辑发布;不能在运行时把草稿当启用规则。 - return DefaultConfig(appcode.FromContext(ctx), poolID), nil + // 未配置时返回 disabled v2 草稿,后台可以直接编辑发布;运行抽奖不会读取这个草稿。 + return DefaultRuleConfig(appcode.FromContext(ctx), poolID), nil } return config, nil } -func (s *Service) UpsertConfig(ctx context.Context, config domain.Config) (domain.Config, error) { +func (s *Service) UpsertConfig(ctx context.Context, config domain.RuleConfig) (domain.RuleConfig, error) { if err := s.requireRepository(); err != nil { - return domain.Config{}, err + return domain.RuleConfig{}, err } config.AppCode = appcode.FromContext(ctx) config.PoolID = normalizePoolID(config.PoolID) - // 规则表历史上用 gift_id 承载作用域;当前以 pool_id 为真实业务键,发布时必须覆盖掉外部传入的 gift_id。 - config.GiftID = config.PoolID - // 后台现在配置倍率列表,服务端生成三档体验池候选;概率权重必须留给抽奖时的 RTP 控制器。 - config.Tiers, config.MultiplierPPMs = normalizeTiers(config.Tiers, config.MultiplierPPMs, config.GiftPrice, config.HighMultiplier) - if err := validateConfig(config); err != nil { - return domain.Config{}, err + config = normalizeRuleConfig(config) + if err := validateRuleConfig(config); err != nil { + return domain.RuleConfig{}, err } - return s.repository.UpsertLuckyGiftConfig(ctx, config, s.now().UTC().UnixMilli()) + return s.repository.PublishLuckyGiftRuleConfig(ctx, config, s.now().UTC().UnixMilli()) } -func (s *Service) ListConfigs(ctx context.Context) ([]domain.Config, error) { +func (s *Service) ListConfigs(ctx context.Context) ([]domain.RuleConfig, error) { if err := s.requireRepository(); err != nil { return nil, err } - return s.repository.ListLuckyGiftConfigs(ctx) + return s.repository.ListLuckyGiftRuleConfigs(ctx) } func (s *Service) ListDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error) { diff --git a/services/activity-service/internal/service/luckygift/service_test.go b/services/activity-service/internal/service/luckygift/service_test.go index e7f16607..3f472baa 100644 --- a/services/activity-service/internal/service/luckygift/service_test.go +++ b/services/activity-service/internal/service/luckygift/service_test.go @@ -26,22 +26,22 @@ func TestGetConfigReturnsPoolDefault(t *testing.T) { if repository.getConfigCalls != 1 { t.Fatalf("expected repository to be called once, got %d", repository.getConfigCalls) } - if config.PoolID != "pool_95" || config.GiftID != "pool_95" { - t.Fatalf("expected pool config scope, got pool=%q gift=%q", config.PoolID, config.GiftID) + if config.PoolID != "pool_95" { + t.Fatalf("expected pool config scope, got pool=%q", config.PoolID) } } func TestUpsertConfigPreservesPoolScope(t *testing.T) { repository := &fakeLuckyGiftRepository{} service := New(repository) - config := DefaultConfig("hyapp", "pool_98") + config := DefaultRuleConfig("hyapp", "pool_98") config.Enabled = true if _, err := service.UpsertConfig(appcode.WithContext(context.Background(), "hyapp"), config); err != nil { t.Fatalf("UpsertConfig returned error: %v", err) } - if repository.upserted.PoolID != "pool_98" || repository.upserted.GiftID != "pool_98" { - t.Fatalf("expected pool scope, got pool=%q gift=%q", repository.upserted.PoolID, repository.upserted.GiftID) + if repository.upserted.PoolID != "pool_98" { + t.Fatalf("expected pool scope, got pool=%q", repository.upserted.PoolID) } } @@ -110,24 +110,24 @@ func TestProcessPendingDrawOutboxCreditsWalletAndPublishesRoomIM(t *testing.T) { type fakeLuckyGiftRepository struct { getConfigCalls int - upserted domain.Config + upserted domain.RuleConfig outbox []domain.DrawOutbox grantedDrawID string deliveredOutboxID string } -func (r *fakeLuckyGiftRepository) GetLuckyGiftConfig(context.Context, string) (domain.Config, bool, error) { +func (r *fakeLuckyGiftRepository) GetLuckyGiftRuleConfig(context.Context, string) (domain.RuleConfig, bool, error) { r.getConfigCalls++ - return domain.Config{}, false, nil + return domain.RuleConfig{}, false, nil } -func (r *fakeLuckyGiftRepository) UpsertLuckyGiftConfig(_ context.Context, config domain.Config, _ int64) (domain.Config, error) { +func (r *fakeLuckyGiftRepository) PublishLuckyGiftRuleConfig(_ context.Context, config domain.RuleConfig, _ int64) (domain.RuleConfig, error) { r.upserted = config return config, nil } -func (r *fakeLuckyGiftRepository) ListLuckyGiftConfigs(context.Context) ([]domain.Config, error) { +func (r *fakeLuckyGiftRepository) ListLuckyGiftRuleConfigs(context.Context) ([]domain.RuleConfig, error) { return nil, nil } diff --git a/services/activity-service/internal/storage/mysql/lucky_gift_repository.go b/services/activity-service/internal/storage/mysql/lucky_gift_repository.go index 2971ef5f..97a7c53d 100644 --- a/services/activity-service/internal/storage/mysql/lucky_gift_repository.go +++ b/services/activity-service/internal/storage/mysql/lucky_gift_repository.go @@ -122,154 +122,12 @@ func (c luckyCandidate) effectiveReward() int64 { return c.BaseReward + c.RoomReward + c.ActivityReward } -// GetLuckyGiftConfig 返回指定幸运礼物奖池规则;未配置由用例层转为默认草稿。 -func (r *Repository) GetLuckyGiftConfig(ctx context.Context, poolID string) (domain.Config, bool, error) { - if r == nil || r.db == nil { - return domain.Config{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured") - } - poolID = luckyPoolID(poolID) - return r.getLuckyGiftConfig(ctx, r.db, appcode.FromContext(ctx), poolID, false) -} - -// UpsertLuckyGiftConfig 发布新的不可变规则版本。运行中窗口不回退,新版本只影响后续抽奖。 -func (r *Repository) UpsertLuckyGiftConfig(ctx context.Context, config domain.Config, nowMS int64) (domain.Config, error) { - if r == nil || r.db == nil { - return domain.Config{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") - } - tx, err := r.db.BeginTx(ctx, nil) - if err != nil { - return domain.Config{}, err - } - defer func() { _ = tx.Rollback() }() - - appCode := appcode.FromContext(ctx) - config.PoolID = luckyPoolID(config.PoolID) - config.GiftID = config.PoolID - current, exists, err := r.getLuckyGiftConfig(ctx, tx, appCode, config.GiftID, true) - if err != nil { - return domain.Config{}, err - } - nextVersion := int64(1) - createdAt := nowMS - if exists { - nextVersion = current.RuleVersion + 1 - createdAt = current.CreatedAtMS - } - config.AppCode = appCode - config.RuleVersion = nextVersion - config.CreatedAtMS = createdAt - config.UpdatedAtMS = nowMS - tiersJSON, err := json.Marshal(config.Tiers) - if err != nil { - return domain.Config{}, err - } - if _, err := tx.ExecContext(ctx, ` - INSERT INTO lucky_gift_rules ( - app_code, gift_id, enabled, rule_version, gift_price, target_rtp_ppm, pool_rate_ppm, - global_window_draws, gift_window_draws, novice_draw_limit, intermediate_draw_limit, - high_multiplier, high_water_pool_multiple, platform_pool_weight_ppm, room_pool_weight_ppm, - gift_pool_weight_ppm, initial_platform_pool, initial_gift_pool, initial_room_pool, - platform_reserve, gift_reserve, room_reserve, max_single_payout, user_hourly_payout_cap, - user_daily_payout_cap, device_daily_payout_cap, room_hourly_payout_cap, anchor_daily_payout_cap, - room_atmosphere_rate_ppm, room_atmosphere_initial, room_atmosphere_reserve, - activity_budget, activity_daily_limit, large_tier_enabled, tiers_json, - updated_by_admin_id, created_at_ms, updated_at_ms - ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) - ON DUPLICATE KEY UPDATE - enabled = VALUES(enabled), - rule_version = VALUES(rule_version), - gift_price = VALUES(gift_price), - target_rtp_ppm = VALUES(target_rtp_ppm), - pool_rate_ppm = VALUES(pool_rate_ppm), - global_window_draws = VALUES(global_window_draws), - gift_window_draws = VALUES(gift_window_draws), - novice_draw_limit = VALUES(novice_draw_limit), - intermediate_draw_limit = VALUES(intermediate_draw_limit), - high_multiplier = VALUES(high_multiplier), - high_water_pool_multiple = VALUES(high_water_pool_multiple), - platform_pool_weight_ppm = VALUES(platform_pool_weight_ppm), - room_pool_weight_ppm = VALUES(room_pool_weight_ppm), - gift_pool_weight_ppm = VALUES(gift_pool_weight_ppm), - initial_platform_pool = VALUES(initial_platform_pool), - initial_gift_pool = VALUES(initial_gift_pool), - initial_room_pool = VALUES(initial_room_pool), - platform_reserve = VALUES(platform_reserve), - gift_reserve = VALUES(gift_reserve), - room_reserve = VALUES(room_reserve), - max_single_payout = VALUES(max_single_payout), - user_hourly_payout_cap = VALUES(user_hourly_payout_cap), - user_daily_payout_cap = VALUES(user_daily_payout_cap), - device_daily_payout_cap = VALUES(device_daily_payout_cap), - room_hourly_payout_cap = VALUES(room_hourly_payout_cap), - anchor_daily_payout_cap = VALUES(anchor_daily_payout_cap), - room_atmosphere_rate_ppm = VALUES(room_atmosphere_rate_ppm), - room_atmosphere_initial = VALUES(room_atmosphere_initial), - room_atmosphere_reserve = VALUES(room_atmosphere_reserve), - activity_budget = VALUES(activity_budget), - activity_daily_limit = VALUES(activity_daily_limit), - large_tier_enabled = VALUES(large_tier_enabled), - tiers_json = VALUES(tiers_json), - updated_by_admin_id = VALUES(updated_by_admin_id), - updated_at_ms = VALUES(updated_at_ms)`, - appCode, config.GiftID, config.Enabled, config.RuleVersion, config.GiftPrice, config.TargetRTPPPM, config.PoolRatePPM, - config.GlobalWindowDraws, config.GiftWindowDraws, config.NoviceDrawLimit, config.IntermediateDrawLimit, - config.HighMultiplier, config.HighWaterPoolMultiple, config.PlatformPoolWeightPPM, config.RoomPoolWeightPPM, - config.GiftPoolWeightPPM, config.InitialPlatformPool, config.InitialGiftPool, config.InitialRoomPool, - config.PlatformReserve, config.GiftReserve, config.RoomReserve, config.MaxSinglePayout, config.UserHourlyPayoutCap, - config.UserDailyPayoutCap, config.DeviceDailyPayoutCap, config.RoomHourlyPayoutCap, config.AnchorDailyPayoutCap, - config.RoomAtmosphereRatePPM, config.RoomAtmosphereInitial, config.RoomAtmosphereReserve, - config.ActivityBudget, config.ActivityDailyLimit, config.LargeTierEnabled, string(tiersJSON), - config.UpdatedByAdminID, config.CreatedAtMS, config.UpdatedAtMS, - ); err != nil { - return domain.Config{}, err - } - if err := r.ensureLuckyActivityBudget(ctx, tx, appCode, config, nowMS); err != nil { - return domain.Config{}, err - } - if err := tx.Commit(); err != nil { - return domain.Config{}, err - } - return config, nil -} - -func (r *Repository) ListLuckyGiftConfigs(ctx context.Context) ([]domain.Config, error) { - if r == nil || r.db == nil { - return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured") - } - appCode := appcode.FromContext(ctx) - rows, err := r.db.QueryContext(ctx, ` - SELECT app_code, gift_id, enabled, rule_version, gift_price, target_rtp_ppm, pool_rate_ppm, - global_window_draws, gift_window_draws, novice_draw_limit, intermediate_draw_limit, - high_multiplier, high_water_pool_multiple, platform_pool_weight_ppm, room_pool_weight_ppm, - gift_pool_weight_ppm, initial_platform_pool, initial_gift_pool, initial_room_pool, - platform_reserve, gift_reserve, room_reserve, max_single_payout, user_hourly_payout_cap, - user_daily_payout_cap, device_daily_payout_cap, room_hourly_payout_cap, anchor_daily_payout_cap, - room_atmosphere_rate_ppm, room_atmosphere_initial, room_atmosphere_reserve, - activity_budget, activity_daily_limit, large_tier_enabled, - COALESCE(CAST(tiers_json AS CHAR), '[]'), updated_by_admin_id, created_at_ms, updated_at_ms - FROM lucky_gift_rules - WHERE app_code = ? - ORDER BY updated_at_ms DESC, gift_id ASC`, - appCode, - ) - if err != nil { - return nil, err - } - defer rows.Close() - configs := make([]domain.Config, 0) - for rows.Next() { - config, err := scanLuckyConfig(rows) - if err != nil { - return nil, err - } - configs = append(configs, config) - } - return configs, rows.Err() -} - func (r *Repository) CheckLuckyGift(ctx context.Context, cmd domain.CheckCommand) (domain.CheckResult, error) { + if r == nil || r.db == nil { + return domain.CheckResult{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } poolID := luckyPoolID(cmd.PoolID) - config, exists, err := r.GetLuckyGiftConfig(ctx, poolID) + config, exists, err := r.getLuckyGiftConfig(ctx, r.db, appcode.FromContext(ctx), poolID, false) if err != nil { return domain.CheckResult{}, err } diff --git a/services/activity-service/internal/storage/mysql/lucky_gift_rule_config_repository.go b/services/activity-service/internal/storage/mysql/lucky_gift_rule_config_repository.go new file mode 100644 index 00000000..e3f8ee2d --- /dev/null +++ b/services/activity-service/internal/storage/mysql/lucky_gift_rule_config_repository.go @@ -0,0 +1,215 @@ +package mysql + +import ( + "context" + "database/sql" + "errors" + + "hyapp/pkg/appcode" + "hyapp/pkg/xerr" + domain "hyapp/services/activity-service/internal/domain/luckygift" +) + +type luckyRuleQueryer interface { + QueryContext(context.Context, string, ...any) (*sql.Rows, error) + QueryRowContext(context.Context, string, ...any) *sql.Row +} + +// GetLuckyGiftRuleConfig 读取指定奖池最新 v2 规则版本;旧抽奖运行表不会参与后台配置读取。 +func (r *Repository) GetLuckyGiftRuleConfig(ctx context.Context, poolID string) (domain.RuleConfig, bool, error) { + if r == nil || r.db == nil { + return domain.RuleConfig{}, false, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + return r.getLuckyGiftRuleConfig(ctx, r.db, appcode.FromContext(ctx), luckyPoolID(poolID), false) +} + +// PublishLuckyGiftRuleConfig 只新增不可变版本,不覆盖历史配置;后续 v2 抽奖引擎按版本读取快照。 +func (r *Repository) PublishLuckyGiftRuleConfig(ctx context.Context, config domain.RuleConfig, nowMS int64) (domain.RuleConfig, error) { + if r == nil || r.db == nil { + return domain.RuleConfig{}, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + tx, err := r.db.BeginTx(ctx, nil) + if err != nil { + return domain.RuleConfig{}, err + } + defer func() { _ = tx.Rollback() }() + + appCode := appcode.FromContext(ctx) + config.AppCode = appCode + config.PoolID = luckyPoolID(config.PoolID) + config.RuleVersion = 1 + config.CreatedAtMS = nowMS + if config.EffectiveFromMS <= 0 { + config.EffectiveFromMS = nowMS + } + var currentVersion int64 + err = tx.QueryRowContext(ctx, ` + SELECT rule_version + FROM lucky_gift_rule_versions + WHERE app_code = ? AND pool_id = ? + ORDER BY rule_version DESC + LIMIT 1 + FOR UPDATE`, + appCode, config.PoolID, + ).Scan(¤tVersion) + if err != nil && !errors.Is(err, sql.ErrNoRows) { + return domain.RuleConfig{}, err + } + if err == nil { + config.RuleVersion = currentVersion + 1 + } + if _, err := tx.ExecContext(ctx, ` + INSERT INTO lucky_gift_rule_versions ( + app_code, pool_id, rule_version, enabled, target_rtp_ppm, pool_rate_ppm, + settlement_window_wager, control_band_ppm, gift_price_reference, + effective_from_ms, created_by_admin_id, created_at_ms + ) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)`, + config.AppCode, config.PoolID, config.RuleVersion, config.Enabled, config.TargetRTPPPM, config.PoolRatePPM, + config.SettlementWindowWager, config.ControlBandPPM, config.GiftPriceReference, + config.EffectiveFromMS, config.CreatedByAdminID, config.CreatedAtMS, + ); err != nil { + return domain.RuleConfig{}, err + } + for _, stage := range config.Stages { + for _, tier := range stage.Tiers { + if _, err := tx.ExecContext(ctx, ` + INSERT INTO lucky_gift_stage_tiers ( + app_code, pool_id, rule_version, stage, tier_id, multiplier_ppm, base_weight_ppm, + reward_source, high_water_only, broadcast_level, enabled + ) VALUES (?,?,?,?,?,?,?,?,?,?,?)`, + config.AppCode, config.PoolID, config.RuleVersion, tier.Stage, tier.TierID, tier.MultiplierPPM, tier.BaseWeightPPM, + tier.RewardSource, tier.HighWaterOnly, tier.BroadcastLevel, tier.Enabled, + ); err != nil { + return domain.RuleConfig{}, err + } + } + } + if err := tx.Commit(); err != nil { + return domain.RuleConfig{}, err + } + return config, nil +} + +// ListLuckyGiftRuleConfigs 返回每个奖池的最新 v2 规则版本,用于后台奖池列表。 +func (r *Repository) ListLuckyGiftRuleConfigs(ctx context.Context) ([]domain.RuleConfig, error) { + if r == nil || r.db == nil { + return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured") + } + appCode := appcode.FromContext(ctx) + rows, err := r.db.QueryContext(ctx, ` + SELECT v.app_code, v.pool_id, v.rule_version, v.enabled, v.target_rtp_ppm, v.pool_rate_ppm, + v.settlement_window_wager, v.control_band_ppm, v.gift_price_reference, + v.effective_from_ms, v.created_by_admin_id, v.created_at_ms + FROM lucky_gift_rule_versions v + INNER JOIN ( + SELECT app_code, pool_id, MAX(rule_version) AS rule_version + FROM lucky_gift_rule_versions + WHERE app_code = ? + GROUP BY app_code, pool_id + ) latest ON latest.app_code = v.app_code AND latest.pool_id = v.pool_id AND latest.rule_version = v.rule_version + ORDER BY v.created_at_ms DESC, v.pool_id ASC`, + appCode, + ) + if err != nil { + return nil, err + } + defer rows.Close() + configs := make([]domain.RuleConfig, 0) + for rows.Next() { + config, err := scanLuckyGiftRuleConfig(rows) + if err != nil { + return nil, err + } + stages, err := r.getLuckyGiftRuleStages(ctx, r.db, config.AppCode, config.PoolID, config.RuleVersion) + if err != nil { + return nil, err + } + config.Stages = stages + configs = append(configs, config) + } + return configs, rows.Err() +} + +func (r *Repository) getLuckyGiftRuleConfig(ctx context.Context, q luckyRuleQueryer, appCode string, poolID string, forUpdate bool) (domain.RuleConfig, bool, error) { + if poolID == "" { + return domain.RuleConfig{}, false, nil + } + lockSQL := "" + if forUpdate { + lockSQL = " FOR UPDATE" + } + row := q.QueryRowContext(ctx, ` + SELECT app_code, pool_id, rule_version, enabled, target_rtp_ppm, pool_rate_ppm, + settlement_window_wager, control_band_ppm, gift_price_reference, + effective_from_ms, created_by_admin_id, created_at_ms + FROM lucky_gift_rule_versions + WHERE app_code = ? AND pool_id = ? + ORDER BY rule_version DESC + LIMIT 1`+lockSQL, + appCode, poolID, + ) + config, err := scanLuckyGiftRuleConfig(row) + if err != nil { + if errors.Is(err, sql.ErrNoRows) { + return domain.RuleConfig{}, false, nil + } + return domain.RuleConfig{}, false, err + } + stages, err := r.getLuckyGiftRuleStages(ctx, q, appCode, poolID, config.RuleVersion) + if err != nil { + return domain.RuleConfig{}, false, err + } + config.Stages = stages + return config, true, nil +} + +func (r *Repository) getLuckyGiftRuleStages(ctx context.Context, q luckyRuleQueryer, appCode string, poolID string, ruleVersion int64) ([]domain.RuleStage, error) { + rows, err := q.QueryContext(ctx, ` + SELECT stage, tier_id, multiplier_ppm, base_weight_ppm, reward_source, high_water_only, broadcast_level, enabled + FROM lucky_gift_stage_tiers + WHERE app_code = ? AND pool_id = ? AND rule_version = ? + ORDER BY FIELD(stage, 'novice', 'normal', 'advanced'), multiplier_ppm ASC, tier_id ASC`, + appCode, poolID, ruleVersion, + ) + if err != nil { + return nil, err + } + defer rows.Close() + stageIndex := map[string]int{} + stages := make([]domain.RuleStage, 0, 3) + for rows.Next() { + var tier domain.RuleTier + if err := rows.Scan(&tier.Stage, &tier.TierID, &tier.MultiplierPPM, &tier.BaseWeightPPM, &tier.RewardSource, &tier.HighWaterOnly, &tier.BroadcastLevel, &tier.Enabled); err != nil { + return nil, err + } + index, exists := stageIndex[tier.Stage] + if !exists { + index = len(stages) + stageIndex[tier.Stage] = index + stages = append(stages, domain.RuleStage{Stage: tier.Stage}) + } + stages[index].Tiers = append(stages[index].Tiers, tier) + } + return stages, rows.Err() +} + +func scanLuckyGiftRuleConfig(scanner luckyScanner) (domain.RuleConfig, error) { + var config domain.RuleConfig + if err := scanner.Scan( + &config.AppCode, + &config.PoolID, + &config.RuleVersion, + &config.Enabled, + &config.TargetRTPPPM, + &config.PoolRatePPM, + &config.SettlementWindowWager, + &config.ControlBandPPM, + &config.GiftPriceReference, + &config.EffectiveFromMS, + &config.CreatedByAdminID, + &config.CreatedAtMS, + ); err != nil { + return domain.RuleConfig{}, err + } + return config, nil +} diff --git a/services/activity-service/internal/storage/mysql/repository.go b/services/activity-service/internal/storage/mysql/repository.go index c78b555d..f684b8b4 100644 --- a/services/activity-service/internal/storage/mysql/repository.go +++ b/services/activity-service/internal/storage/mysql/repository.go @@ -51,6 +51,9 @@ func (r *Repository) Migrate(ctx context.Context) error { if err := r.ensureLuckyDrawRewardSettlementColumns(ctx); err != nil { return err } + if err := r.ensureLuckyGiftRuleVersionTables(ctx); err != nil { + return err + } if err := r.ensureDefaultLuckyGiftRules(ctx); err != nil { return err } @@ -148,6 +151,49 @@ func (r *Repository) ensureLuckyDrawRewardSettlementColumns(ctx context.Context) return nil } +func (r *Repository) ensureLuckyGiftRuleVersionTables(ctx context.Context) error { + statements := []string{ + `CREATE TABLE IF NOT EXISTS lucky_gift_rule_versions ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码', + pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID', + rule_version BIGINT NOT NULL COMMENT '不可变规则版本', + enabled TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否启用', + target_rtp_ppm BIGINT NOT NULL COMMENT '基础返奖目标,ppm', + pool_rate_ppm BIGINT NOT NULL COMMENT '每笔扣费进入基础奖池比例,ppm', + settlement_window_wager BIGINT NOT NULL COMMENT 'RTP 结算窗口流水,单位金币', + control_band_ppm BIGINT NOT NULL COMMENT '正常波动带,ppm', + gift_price_reference BIGINT NOT NULL COMMENT '配置参考礼物价格', + effective_from_ms BIGINT NOT NULL COMMENT '生效时间,UTC epoch ms', + created_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '发布人', + created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms', + PRIMARY KEY (app_code, pool_id, rule_version), + KEY idx_lucky_gift_rule_versions_latest (app_code, pool_id, rule_version), + KEY idx_lucky_gift_rule_versions_enabled (app_code, enabled, created_at_ms) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 v2 规则版本表'`, + `CREATE TABLE IF NOT EXISTS lucky_gift_stage_tiers ( + app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码', + pool_id VARCHAR(96) NOT NULL COMMENT '幸运礼物奖池 ID', + rule_version BIGINT NOT NULL COMMENT '规则版本', + stage VARCHAR(32) NOT NULL COMMENT 'novice/normal/advanced', + tier_id VARCHAR(96) NOT NULL COMMENT '奖档 ID', + multiplier_ppm BIGINT NOT NULL COMMENT '倍率,1x = 1000000', + base_weight_ppm BIGINT NOT NULL COMMENT '正常模式基础概率,ppm', + reward_source VARCHAR(32) NOT NULL COMMENT 'base_rtp/activity_subsidy/presentation_only', + high_water_only TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否高水位才开放', + broadcast_level VARCHAR(32) NOT NULL DEFAULT 'none' COMMENT 'none/room/region/global', + enabled TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用', + PRIMARY KEY (app_code, pool_id, rule_version, stage, tier_id), + KEY idx_lucky_gift_stage_tiers_stage (app_code, pool_id, rule_version, stage) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='幸运礼物 v2 阶段奖档表'`, + } + for _, statement := range statements { + if _, err := r.db.ExecContext(ctx, statement); err != nil { + return err + } + } + return nil +} + func (r *Repository) ensureDefaultLuckyGiftRules(ctx context.Context) error { // 本地和 Docker 开发库通常保留 MySQL volume;这里补齐缺省 lucky/super_lucky 契约,但不覆盖后台已发布规则。 const seedNowMS int64 = 1779259000000 diff --git a/services/activity-service/internal/transport/grpc/lucky_gift_server.go b/services/activity-service/internal/transport/grpc/lucky_gift_server.go index b7313eda..2872c9e5 100644 --- a/services/activity-service/internal/transport/grpc/lucky_gift_server.go +++ b/services/activity-service/internal/transport/grpc/lucky_gift_server.go @@ -84,18 +84,18 @@ func (s *AdminLuckyGiftServer) GetLuckyGiftConfig(ctx context.Context, req *acti if err != nil { return nil, xerr.ToGRPCError(err) } - return &activityv1.GetLuckyGiftConfigResponse{Config: luckyConfigToProto(config)}, nil + return &activityv1.GetLuckyGiftConfigResponse{Config: luckyRuleConfigToProto(config)}, nil } func (s *AdminLuckyGiftServer) UpsertLuckyGiftConfig(ctx context.Context, req *activityv1.UpsertLuckyGiftConfigRequest) (*activityv1.UpsertLuckyGiftConfigResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) - config := luckyConfigFromProto(req.GetConfig()) - config.UpdatedByAdminID = req.GetOperatorAdminId() + config := luckyRuleConfigFromProto(req.GetConfig()) + config.CreatedByAdminID = req.GetOperatorAdminId() updated, err := s.svc.UpsertConfig(ctx, config) if err != nil { return nil, xerr.ToGRPCError(err) } - return &activityv1.UpsertLuckyGiftConfigResponse{Config: luckyConfigToProto(updated)}, nil + return &activityv1.UpsertLuckyGiftConfigResponse{Config: luckyRuleConfigToProto(updated)}, nil } func (s *AdminLuckyGiftServer) ListLuckyGiftConfigs(ctx context.Context, req *activityv1.ListLuckyGiftConfigsRequest) (*activityv1.ListLuckyGiftConfigsResponse, error) { @@ -104,9 +104,9 @@ func (s *AdminLuckyGiftServer) ListLuckyGiftConfigs(ctx context.Context, req *ac if err != nil { return nil, xerr.ToGRPCError(err) } - resp := &activityv1.ListLuckyGiftConfigsResponse{Configs: make([]*activityv1.LuckyGiftConfig, 0, len(configs))} + resp := &activityv1.ListLuckyGiftConfigsResponse{Configs: make([]*activityv1.LuckyGiftRuleConfig, 0, len(configs))} for _, config := range configs { - resp.Configs = append(resp.Configs, luckyConfigToProto(config)) + resp.Configs = append(resp.Configs, luckyRuleConfigToProto(config)) } return resp, nil } @@ -147,120 +147,82 @@ func (s *AdminLuckyGiftServer) GetLuckyGiftDrawSummary(ctx context.Context, req return &activityv1.GetLuckyGiftDrawSummaryResponse{Summary: luckyDrawSummaryToProto(summary)}, nil } -func luckyConfigFromProto(config *activityv1.LuckyGiftConfig) domain.Config { +func luckyRuleConfigFromProto(config *activityv1.LuckyGiftRuleConfig) domain.RuleConfig { if config == nil { - return domain.Config{} + return domain.RuleConfig{} } - tiers := make([]domain.Tier, 0, len(config.GetTiers())) - for _, tier := range config.GetTiers() { - tiers = append(tiers, domain.Tier{ - Pool: tier.GetPool(), - TierID: tier.GetTierId(), - RewardCoins: tier.GetRewardCoins(), - MultiplierPPM: tier.GetMultiplierPpm(), - Weight: tier.GetWeight(), - HighWaterOnly: tier.GetHighWaterOnly(), - Enabled: tier.GetEnabled(), + stages := make([]domain.RuleStage, 0, len(config.GetStages())) + for _, stage := range config.GetStages() { + tiers := make([]domain.RuleTier, 0, len(stage.GetTiers())) + for _, tier := range stage.GetTiers() { + tiers = append(tiers, domain.RuleTier{ + Stage: tier.GetStage(), + TierID: tier.GetTierId(), + MultiplierPPM: tier.GetMultiplierPpm(), + BaseWeightPPM: tier.GetBaseWeightPpm(), + RewardSource: tier.GetRewardSource(), + HighWaterOnly: tier.GetHighWaterOnly(), + BroadcastLevel: tier.GetBroadcastLevel(), + Enabled: tier.GetEnabled(), + }) + } + stages = append(stages, domain.RuleStage{ + Stage: stage.GetStage(), + Tiers: tiers, }) } - return domain.Config{ + return domain.RuleConfig{ AppCode: config.GetAppCode(), - GiftID: config.GetGiftId(), PoolID: config.GetPoolId(), - Enabled: config.GetEnabled(), RuleVersion: config.GetRuleVersion(), - GiftPrice: config.GetGiftPrice(), + Enabled: config.GetEnabled(), TargetRTPPPM: config.GetTargetRtpPpm(), PoolRatePPM: config.GetPoolRatePpm(), - GlobalWindowDraws: config.GetGlobalWindowDraws(), - GiftWindowDraws: config.GetGiftWindowDraws(), - NoviceDrawLimit: config.GetNoviceDrawLimit(), - IntermediateDrawLimit: config.GetIntermediateDrawLimit(), - HighMultiplier: config.GetHighMultiplier(), - HighWaterPoolMultiple: config.GetHighWaterPoolMultiple(), - PlatformPoolWeightPPM: config.GetPlatformPoolWeightPpm(), - RoomPoolWeightPPM: config.GetRoomPoolWeightPpm(), - GiftPoolWeightPPM: config.GetGiftPoolWeightPpm(), - InitialPlatformPool: config.GetInitialPlatformPool(), - InitialGiftPool: config.GetInitialGiftPool(), - InitialRoomPool: config.GetInitialRoomPool(), - PlatformReserve: config.GetPlatformReserve(), - GiftReserve: config.GetGiftReserve(), - RoomReserve: config.GetRoomReserve(), - MaxSinglePayout: config.GetMaxSinglePayout(), - UserHourlyPayoutCap: config.GetUserHourlyPayoutCap(), - UserDailyPayoutCap: config.GetUserDailyPayoutCap(), - DeviceDailyPayoutCap: config.GetDeviceDailyPayoutCap(), - RoomHourlyPayoutCap: config.GetRoomHourlyPayoutCap(), - AnchorDailyPayoutCap: config.GetAnchorDailyPayoutCap(), - RoomAtmosphereRatePPM: config.GetRoomAtmosphereRatePpm(), - RoomAtmosphereInitial: config.GetRoomAtmosphereInitial(), - RoomAtmosphereReserve: config.GetRoomAtmosphereReserve(), - ActivityBudget: config.GetActivityBudget(), - ActivityDailyLimit: config.GetActivityDailyLimit(), - LargeTierEnabled: config.GetLargeTierEnabled(), - MultiplierPPMs: append([]int64(nil), config.GetMultiplierPpms()...), - Tiers: tiers, - UpdatedByAdminID: config.GetUpdatedByAdminId(), + SettlementWindowWager: config.GetSettlementWindowWager(), + ControlBandPPM: config.GetControlBandPpm(), + GiftPriceReference: config.GetGiftPriceReference(), + EffectiveFromMS: config.GetEffectiveFromMs(), + CreatedByAdminID: config.GetCreatedByAdminId(), CreatedAtMS: config.GetCreatedAtMs(), - UpdatedAtMS: config.GetUpdatedAtMs(), + Stages: stages, } } -func luckyConfigToProto(config domain.Config) *activityv1.LuckyGiftConfig { - tiers := make([]*activityv1.LuckyGiftTier, 0, len(config.Tiers)) - for _, tier := range config.Tiers { - tiers = append(tiers, &activityv1.LuckyGiftTier{ - Pool: tier.Pool, - TierId: tier.TierID, - RewardCoins: tier.RewardCoins, - MultiplierPpm: tier.MultiplierPPM, - Weight: tier.Weight, - HighWaterOnly: tier.HighWaterOnly, - Enabled: tier.Enabled, +func luckyRuleConfigToProto(config domain.RuleConfig) *activityv1.LuckyGiftRuleConfig { + stages := make([]*activityv1.LuckyGiftRuleStage, 0, len(config.Stages)) + for _, stage := range config.Stages { + tiers := make([]*activityv1.LuckyGiftRuleTier, 0, len(stage.Tiers)) + for _, tier := range stage.Tiers { + tiers = append(tiers, &activityv1.LuckyGiftRuleTier{ + Stage: tier.Stage, + TierId: tier.TierID, + MultiplierPpm: tier.MultiplierPPM, + BaseWeightPpm: tier.BaseWeightPPM, + RewardSource: tier.RewardSource, + HighWaterOnly: tier.HighWaterOnly, + BroadcastLevel: tier.BroadcastLevel, + Enabled: tier.Enabled, + }) + } + stages = append(stages, &activityv1.LuckyGiftRuleStage{ + Stage: stage.Stage, + Tiers: tiers, }) } - return &activityv1.LuckyGiftConfig{ + return &activityv1.LuckyGiftRuleConfig{ AppCode: config.AppCode, - GiftId: config.GiftID, PoolId: config.PoolID, - Enabled: config.Enabled, RuleVersion: config.RuleVersion, - GiftPrice: config.GiftPrice, + Enabled: config.Enabled, TargetRtpPpm: config.TargetRTPPPM, PoolRatePpm: config.PoolRatePPM, - GlobalWindowDraws: config.GlobalWindowDraws, - GiftWindowDraws: config.GiftWindowDraws, - NoviceDrawLimit: config.NoviceDrawLimit, - IntermediateDrawLimit: config.IntermediateDrawLimit, - HighMultiplier: config.HighMultiplier, - HighWaterPoolMultiple: config.HighWaterPoolMultiple, - PlatformPoolWeightPpm: config.PlatformPoolWeightPPM, - RoomPoolWeightPpm: config.RoomPoolWeightPPM, - GiftPoolWeightPpm: config.GiftPoolWeightPPM, - InitialPlatformPool: config.InitialPlatformPool, - InitialGiftPool: config.InitialGiftPool, - InitialRoomPool: config.InitialRoomPool, - PlatformReserve: config.PlatformReserve, - GiftReserve: config.GiftReserve, - RoomReserve: config.RoomReserve, - MaxSinglePayout: config.MaxSinglePayout, - UserHourlyPayoutCap: config.UserHourlyPayoutCap, - UserDailyPayoutCap: config.UserDailyPayoutCap, - DeviceDailyPayoutCap: config.DeviceDailyPayoutCap, - RoomHourlyPayoutCap: config.RoomHourlyPayoutCap, - AnchorDailyPayoutCap: config.AnchorDailyPayoutCap, - RoomAtmosphereRatePpm: config.RoomAtmosphereRatePPM, - RoomAtmosphereInitial: config.RoomAtmosphereInitial, - RoomAtmosphereReserve: config.RoomAtmosphereReserve, - ActivityBudget: config.ActivityBudget, - ActivityDailyLimit: config.ActivityDailyLimit, - LargeTierEnabled: config.LargeTierEnabled, - MultiplierPpms: append([]int64(nil), config.MultiplierPPMs...), - Tiers: tiers, - UpdatedByAdminId: config.UpdatedByAdminID, + SettlementWindowWager: config.SettlementWindowWager, + ControlBandPpm: config.ControlBandPPM, + GiftPriceReference: config.GiftPriceReference, + EffectiveFromMs: config.EffectiveFromMS, + CreatedByAdminId: config.CreatedByAdminID, CreatedAtMs: config.CreatedAtMS, - UpdatedAtMs: config.UpdatedAtMS, + Stages: stages, } } From 09fb0c3c81df2b44495f917309bf76dbf664a11e Mon Sep 17 00:00:00 2001 From: zhx Date: Thu, 28 May 2026 15:11:10 +0800 Subject: [PATCH 2/3] =?UTF-8?q?=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../configs/config.docker.yaml | 7 +++ services/gateway-service/configs/config.yaml | 7 +++ tools/baishun-game-test.html | 16 ++++- tools/lucky-gift-test.html | 63 +++++++++++++++++-- 4 files changed, 86 insertions(+), 7 deletions(-) diff --git a/services/gateway-service/configs/config.docker.yaml b/services/gateway-service/configs/config.docker.yaml index af67244f..c959e744 100644 --- a/services/gateway-service/configs/config.docker.yaml +++ b/services/gateway-service/configs/config.docker.yaml @@ -15,6 +15,13 @@ cors: - "http://127.0.0.1:3000" - "http://localhost:5173" - "http://127.0.0.1:5173" + # 本地工具页会用 10300/8787/8788 承载静态 HTML;精确放行测试端口,避免用 "*" 破坏凭证请求边界。 + - "http://localhost:10300" + - "http://127.0.0.1:10300" + - "http://localhost:8787" + - "http://127.0.0.1:8787" + - "http://localhost:8788" + - "http://127.0.0.1:8788" - "https://global-interaction.com" - "https://www.global-interaction.com" - "https://h5.global-interaction.com" diff --git a/services/gateway-service/configs/config.yaml b/services/gateway-service/configs/config.yaml index 33b301b6..8e7f2051 100644 --- a/services/gateway-service/configs/config.yaml +++ b/services/gateway-service/configs/config.yaml @@ -15,6 +15,13 @@ cors: - "http://127.0.0.1:3000" - "http://localhost:5173" - "http://127.0.0.1:5173" + # 本地工具页会用 10300/8787/8788 承载静态 HTML;精确放行测试端口,避免用 "*" 破坏凭证请求边界。 + - "http://localhost:10300" + - "http://127.0.0.1:10300" + - "http://localhost:8787" + - "http://127.0.0.1:8787" + - "http://localhost:8788" + - "http://127.0.0.1:8788" - "https://global-interaction.com" - "https://www.global-interaction.com" - "https://h5.global-interaction.com" diff --git a/tools/baishun-game-test.html b/tools/baishun-game-test.html index ce6efbd8..aa109c1b 100644 --- a/tools/baishun-game-test.html +++ b/tools/baishun-game-test.html @@ -155,13 +155,27 @@ const $ = (id) => document.getElementById(id); const defaultApiBase = "https://api-test.global-interaction.com"; const isLocalProxy = ["localhost", "127.0.0.1", "::1"].includes(window.location.hostname); + const bundledProxyPorts = new Set(["8787", "8788"]); + const isBundledProxy = isLocalProxy && bundledProxyPorts.has(window.location.port); + const localDirectApiBasePattern = /^https?:\/\/(?:localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/; $("token").value = localStorage.getItem("baishun_test_access_token") || ""; $("account").value = localStorage.getItem("baishun_test_account") || ""; const savedApiBase = localStorage.getItem("baishun_test_api_base") || ""; - $("apiBase").value = isLocalProxy && (!savedApiBase || savedApiBase === defaultApiBase) ? "" : (savedApiBase || defaultApiBase); + $("apiBase").value = initialApiBase(savedApiBase); $("appCode").value = localStorage.getItem("baishun_test_app_code") || $("appCode").value; + function initialApiBase(savedValue) { + const saved = savedValue.trim().replace(/\/+$/, ""); + // 仓库自带 Node 代理默认监听 8787,本地占用时可切到 8788;空 API Base 会让请求走同源 /api 转发。Python 等纯静态服务 + // 没有这个代理能力,因此必须保留用户手动填写的本地 gateway 地址,交给 gateway CORS 白名单处理。 + if (isLocalProxy && (!saved || saved === defaultApiBase || (isBundledProxy && localDirectApiBasePattern.test(saved)))) { + localStorage.setItem("baishun_test_api_base", ""); + return ""; + } + return saved || defaultApiBase; + } + function apiBase() { return $("apiBase").value.trim().replace(/\/+$/, ""); } diff --git a/tools/lucky-gift-test.html b/tools/lucky-gift-test.html index 13b5de23..480dfc4e 100644 --- a/tools/lucky-gift-test.html +++ b/tools/lucky-gift-test.html @@ -158,6 +158,15 @@ pool_id +