幸运礼物
This commit is contained in:
parent
a0ee5962df
commit
a68d465272
@ -9955,6 +9955,8 @@ type LuckyGiftMeta struct {
|
||||
CoinSpent int64 `protobuf:"varint,8,opt,name=coin_spent,json=coinSpent,proto3" json:"coin_spent,omitempty"`
|
||||
PaidAtMs int64 `protobuf:"varint,9,opt,name=paid_at_ms,json=paidAtMs,proto3" json:"paid_at_ms,omitempty"`
|
||||
PoolId string `protobuf:"bytes,10,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"`
|
||||
TargetUserId int64 `protobuf:"varint,11,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"`
|
||||
GiftCount int32 `protobuf:"varint,12,opt,name=gift_count,json=giftCount,proto3" json:"gift_count,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@ -10059,6 +10061,20 @@ func (x *LuckyGiftMeta) GetPoolId() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *LuckyGiftMeta) GetTargetUserId() int64 {
|
||||
if x != nil {
|
||||
return x.TargetUserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *LuckyGiftMeta) GetGiftCount() int32 {
|
||||
if x != nil {
|
||||
return x.GiftCount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type LuckyGiftTier struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Pool string `protobuf:"bytes,1,opt,name=pool,proto3" json:"pool,omitempty"`
|
||||
@ -12599,7 +12615,7 @@ const file_proto_activity_v1_activity_proto_rawDesc = "" +
|
||||
"conditions\"\x8b\x01\n" +
|
||||
"#UpsertAchievementDefinitionResponse\x12J\n" +
|
||||
"\vachievement\x18\x01 \x01(\v2(.hyapp.activity.v1.AchievementDefinitionR\vachievement\x12\x18\n" +
|
||||
"\acreated\x18\x02 \x01(\bR\acreated\"\xbd\x02\n" +
|
||||
"\acreated\x18\x02 \x01(\bR\acreated\"\x82\x03\n" +
|
||||
"\rLuckyGiftMeta\x122\n" +
|
||||
"\x04meta\x18\x01 \x01(\v2\x1e.hyapp.activity.v1.RequestMetaR\x04meta\x12\x1d\n" +
|
||||
"\n" +
|
||||
@ -12614,7 +12630,10 @@ const file_proto_activity_v1_activity_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"paid_at_ms\x18\t \x01(\x03R\bpaidAtMs\x12\x17\n" +
|
||||
"\apool_id\x18\n" +
|
||||
" \x01(\tR\x06poolId\"\xe0\x01\n" +
|
||||
" \x01(\tR\x06poolId\x12$\n" +
|
||||
"\x0etarget_user_id\x18\v \x01(\x03R\ftargetUserId\x12\x1d\n" +
|
||||
"\n" +
|
||||
"gift_count\x18\f \x01(\x05R\tgiftCount\"\xe0\x01\n" +
|
||||
"\rLuckyGiftTier\x12\x12\n" +
|
||||
"\x04pool\x18\x01 \x01(\tR\x04pool\x12\x17\n" +
|
||||
"\atier_id\x18\x02 \x01(\tR\x06tierId\x12!\n" +
|
||||
|
||||
@ -1123,6 +1123,8 @@ message LuckyGiftMeta {
|
||||
int64 coin_spent = 8;
|
||||
int64 paid_at_ms = 9;
|
||||
string pool_id = 10;
|
||||
int64 target_user_id = 11;
|
||||
int32 gift_count = 12;
|
||||
}
|
||||
|
||||
message LuckyGiftTier {
|
||||
|
||||
@ -9492,6 +9492,184 @@ func (x *CreditTaskRewardResponse) GetGrantedAtMs() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// CreditLuckyGiftRewardRequest 是 activity-service 抽奖 outbox 补偿 worker 调用的钱包入账命令。
|
||||
type CreditLuckyGiftRewardRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
CommandId string `protobuf:"bytes,1,opt,name=command_id,json=commandId,proto3" json:"command_id,omitempty"`
|
||||
AppCode string `protobuf:"bytes,2,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"`
|
||||
TargetUserId int64 `protobuf:"varint,3,opt,name=target_user_id,json=targetUserId,proto3" json:"target_user_id,omitempty"`
|
||||
Amount int64 `protobuf:"varint,4,opt,name=amount,proto3" json:"amount,omitempty"`
|
||||
DrawId string `protobuf:"bytes,5,opt,name=draw_id,json=drawId,proto3" json:"draw_id,omitempty"`
|
||||
RoomId string `protobuf:"bytes,6,opt,name=room_id,json=roomId,proto3" json:"room_id,omitempty"`
|
||||
GiftId string `protobuf:"bytes,7,opt,name=gift_id,json=giftId,proto3" json:"gift_id,omitempty"`
|
||||
PoolId string `protobuf:"bytes,8,opt,name=pool_id,json=poolId,proto3" json:"pool_id,omitempty"`
|
||||
Reason string `protobuf:"bytes,9,opt,name=reason,proto3" json:"reason,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) Reset() {
|
||||
*x = CreditLuckyGiftRewardRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[106]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CreditLuckyGiftRewardRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[106]
|
||||
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 CreditLuckyGiftRewardRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CreditLuckyGiftRewardRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{106}
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetCommandId() string {
|
||||
if x != nil {
|
||||
return x.CommandId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetAppCode() string {
|
||||
if x != nil {
|
||||
return x.AppCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetTargetUserId() int64 {
|
||||
if x != nil {
|
||||
return x.TargetUserId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetAmount() int64 {
|
||||
if x != nil {
|
||||
return x.Amount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetDrawId() string {
|
||||
if x != nil {
|
||||
return x.DrawId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetRoomId() string {
|
||||
if x != nil {
|
||||
return x.RoomId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetGiftId() string {
|
||||
if x != nil {
|
||||
return x.GiftId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetPoolId() string {
|
||||
if x != nil {
|
||||
return x.PoolId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardRequest) GetReason() string {
|
||||
if x != nil {
|
||||
return x.Reason
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// CreditLuckyGiftRewardResponse 返回幸运礼物返奖入账流水和用户 COIN 账后余额。
|
||||
type CreditLuckyGiftRewardResponse struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
TransactionId string `protobuf:"bytes,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"`
|
||||
Balance *AssetBalance `protobuf:"bytes,2,opt,name=balance,proto3" json:"balance,omitempty"`
|
||||
Amount int64 `protobuf:"varint,3,opt,name=amount,proto3" json:"amount,omitempty"`
|
||||
GrantedAtMs int64 `protobuf:"varint,4,opt,name=granted_at_ms,json=grantedAtMs,proto3" json:"granted_at_ms,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) Reset() {
|
||||
*x = CreditLuckyGiftRewardResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[107]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*CreditLuckyGiftRewardResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[107]
|
||||
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 CreditLuckyGiftRewardResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CreditLuckyGiftRewardResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{107}
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) GetTransactionId() string {
|
||||
if x != nil {
|
||||
return x.TransactionId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) GetBalance() *AssetBalance {
|
||||
if x != nil {
|
||||
return x.Balance
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) GetAmount() int64 {
|
||||
if x != nil {
|
||||
return x.Amount
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *CreditLuckyGiftRewardResponse) GetGrantedAtMs() int64 {
|
||||
if x != nil {
|
||||
return x.GrantedAtMs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// ApplyGameCoinChangeRequest 是 game-service 唯一可以调用的钱包游戏改账入口。
|
||||
type ApplyGameCoinChangeRequest struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
@ -9513,7 +9691,7 @@ type ApplyGameCoinChangeRequest struct {
|
||||
|
||||
func (x *ApplyGameCoinChangeRequest) Reset() {
|
||||
*x = ApplyGameCoinChangeRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[106]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[108]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -9525,7 +9703,7 @@ func (x *ApplyGameCoinChangeRequest) String() string {
|
||||
func (*ApplyGameCoinChangeRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ApplyGameCoinChangeRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[106]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[108]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -9538,7 +9716,7 @@ func (x *ApplyGameCoinChangeRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ApplyGameCoinChangeRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ApplyGameCoinChangeRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{106}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{108}
|
||||
}
|
||||
|
||||
func (x *ApplyGameCoinChangeRequest) GetRequestId() string {
|
||||
@ -9637,7 +9815,7 @@ type ApplyGameCoinChangeResponse struct {
|
||||
|
||||
func (x *ApplyGameCoinChangeResponse) Reset() {
|
||||
*x = ApplyGameCoinChangeResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[107]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[109]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -9649,7 +9827,7 @@ func (x *ApplyGameCoinChangeResponse) String() string {
|
||||
func (*ApplyGameCoinChangeResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ApplyGameCoinChangeResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[107]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[109]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -9662,7 +9840,7 @@ func (x *ApplyGameCoinChangeResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ApplyGameCoinChangeResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ApplyGameCoinChangeResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{107}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{109}
|
||||
}
|
||||
|
||||
func (x *ApplyGameCoinChangeResponse) GetWalletTransactionId() string {
|
||||
@ -9704,7 +9882,7 @@ type RedPacketConfig struct {
|
||||
|
||||
func (x *RedPacketConfig) Reset() {
|
||||
*x = RedPacketConfig{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[108]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[110]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -9716,7 +9894,7 @@ func (x *RedPacketConfig) String() string {
|
||||
func (*RedPacketConfig) ProtoMessage() {}
|
||||
|
||||
func (x *RedPacketConfig) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[108]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[110]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -9729,7 +9907,7 @@ func (x *RedPacketConfig) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RedPacketConfig.ProtoReflect.Descriptor instead.
|
||||
func (*RedPacketConfig) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{108}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{110}
|
||||
}
|
||||
|
||||
func (x *RedPacketConfig) GetAppCode() string {
|
||||
@ -9821,7 +9999,7 @@ type RedPacketClaim struct {
|
||||
|
||||
func (x *RedPacketClaim) Reset() {
|
||||
*x = RedPacketClaim{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[109]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[111]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -9833,7 +10011,7 @@ func (x *RedPacketClaim) String() string {
|
||||
func (*RedPacketClaim) ProtoMessage() {}
|
||||
|
||||
func (x *RedPacketClaim) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[109]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[111]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -9846,7 +10024,7 @@ func (x *RedPacketClaim) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RedPacketClaim.ProtoReflect.Descriptor instead.
|
||||
func (*RedPacketClaim) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{109}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{111}
|
||||
}
|
||||
|
||||
func (x *RedPacketClaim) GetAppCode() string {
|
||||
@ -9953,7 +10131,7 @@ type RedPacket struct {
|
||||
|
||||
func (x *RedPacket) Reset() {
|
||||
*x = RedPacket{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[110]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[112]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -9965,7 +10143,7 @@ func (x *RedPacket) String() string {
|
||||
func (*RedPacket) ProtoMessage() {}
|
||||
|
||||
func (x *RedPacket) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[110]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[112]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -9978,7 +10156,7 @@ func (x *RedPacket) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use RedPacket.ProtoReflect.Descriptor instead.
|
||||
func (*RedPacket) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{110}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{112}
|
||||
}
|
||||
|
||||
func (x *RedPacket) GetAppCode() string {
|
||||
@ -10124,7 +10302,7 @@ type GetRedPacketConfigRequest struct {
|
||||
|
||||
func (x *GetRedPacketConfigRequest) Reset() {
|
||||
*x = GetRedPacketConfigRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[111]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[113]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10136,7 +10314,7 @@ func (x *GetRedPacketConfigRequest) String() string {
|
||||
func (*GetRedPacketConfigRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetRedPacketConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[111]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[113]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10149,7 +10327,7 @@ func (x *GetRedPacketConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetRedPacketConfigRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetRedPacketConfigRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{111}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{113}
|
||||
}
|
||||
|
||||
func (x *GetRedPacketConfigRequest) GetRequestId() string {
|
||||
@ -10176,7 +10354,7 @@ type GetRedPacketConfigResponse struct {
|
||||
|
||||
func (x *GetRedPacketConfigResponse) Reset() {
|
||||
*x = GetRedPacketConfigResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[112]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[114]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10188,7 +10366,7 @@ func (x *GetRedPacketConfigResponse) String() string {
|
||||
func (*GetRedPacketConfigResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetRedPacketConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[112]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[114]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10201,7 +10379,7 @@ func (x *GetRedPacketConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetRedPacketConfigResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetRedPacketConfigResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{112}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{114}
|
||||
}
|
||||
|
||||
func (x *GetRedPacketConfigResponse) GetConfig() *RedPacketConfig {
|
||||
@ -10235,7 +10413,7 @@ type UpdateRedPacketConfigRequest struct {
|
||||
|
||||
func (x *UpdateRedPacketConfigRequest) Reset() {
|
||||
*x = UpdateRedPacketConfigRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[113]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[115]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10247,7 +10425,7 @@ func (x *UpdateRedPacketConfigRequest) String() string {
|
||||
func (*UpdateRedPacketConfigRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateRedPacketConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[113]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[115]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10260,7 +10438,7 @@ func (x *UpdateRedPacketConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use UpdateRedPacketConfigRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateRedPacketConfigRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{113}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{115}
|
||||
}
|
||||
|
||||
func (x *UpdateRedPacketConfigRequest) GetRequestId() string {
|
||||
@ -10336,7 +10514,7 @@ type UpdateRedPacketConfigResponse struct {
|
||||
|
||||
func (x *UpdateRedPacketConfigResponse) Reset() {
|
||||
*x = UpdateRedPacketConfigResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[114]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[116]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10348,7 +10526,7 @@ func (x *UpdateRedPacketConfigResponse) String() string {
|
||||
func (*UpdateRedPacketConfigResponse) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateRedPacketConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[114]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[116]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10361,7 +10539,7 @@ func (x *UpdateRedPacketConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use UpdateRedPacketConfigResponse.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateRedPacketConfigResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{114}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{116}
|
||||
}
|
||||
|
||||
func (x *UpdateRedPacketConfigResponse) GetConfig() *RedPacketConfig {
|
||||
@ -10395,7 +10573,7 @@ type CreateRedPacketRequest struct {
|
||||
|
||||
func (x *CreateRedPacketRequest) Reset() {
|
||||
*x = CreateRedPacketRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[115]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[117]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10407,7 +10585,7 @@ func (x *CreateRedPacketRequest) String() string {
|
||||
func (*CreateRedPacketRequest) ProtoMessage() {}
|
||||
|
||||
func (x *CreateRedPacketRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[115]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[117]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10420,7 +10598,7 @@ func (x *CreateRedPacketRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CreateRedPacketRequest.ProtoReflect.Descriptor instead.
|
||||
func (*CreateRedPacketRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{115}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{117}
|
||||
}
|
||||
|
||||
func (x *CreateRedPacketRequest) GetRequestId() string {
|
||||
@ -10497,7 +10675,7 @@ type CreateRedPacketResponse struct {
|
||||
|
||||
func (x *CreateRedPacketResponse) Reset() {
|
||||
*x = CreateRedPacketResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[116]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[118]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10509,7 +10687,7 @@ func (x *CreateRedPacketResponse) String() string {
|
||||
func (*CreateRedPacketResponse) ProtoMessage() {}
|
||||
|
||||
func (x *CreateRedPacketResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[116]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[118]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10522,7 +10700,7 @@ func (x *CreateRedPacketResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use CreateRedPacketResponse.ProtoReflect.Descriptor instead.
|
||||
func (*CreateRedPacketResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{116}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{118}
|
||||
}
|
||||
|
||||
func (x *CreateRedPacketResponse) GetPacket() *RedPacket {
|
||||
@ -10559,7 +10737,7 @@ type ClaimRedPacketRequest struct {
|
||||
|
||||
func (x *ClaimRedPacketRequest) Reset() {
|
||||
*x = ClaimRedPacketRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[117]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[119]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10571,7 +10749,7 @@ func (x *ClaimRedPacketRequest) String() string {
|
||||
func (*ClaimRedPacketRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ClaimRedPacketRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[117]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[119]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10584,7 +10762,7 @@ func (x *ClaimRedPacketRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ClaimRedPacketRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ClaimRedPacketRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{117}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{119}
|
||||
}
|
||||
|
||||
func (x *ClaimRedPacketRequest) GetRequestId() string {
|
||||
@ -10633,7 +10811,7 @@ type ClaimRedPacketResponse struct {
|
||||
|
||||
func (x *ClaimRedPacketResponse) Reset() {
|
||||
*x = ClaimRedPacketResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[118]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[120]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10645,7 +10823,7 @@ func (x *ClaimRedPacketResponse) String() string {
|
||||
func (*ClaimRedPacketResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ClaimRedPacketResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[118]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[120]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10658,7 +10836,7 @@ func (x *ClaimRedPacketResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ClaimRedPacketResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ClaimRedPacketResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{118}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{120}
|
||||
}
|
||||
|
||||
func (x *ClaimRedPacketResponse) GetClaim() *RedPacketClaim {
|
||||
@ -10702,7 +10880,7 @@ type ListRedPacketsRequest struct {
|
||||
|
||||
func (x *ListRedPacketsRequest) Reset() {
|
||||
*x = ListRedPacketsRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[119]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[121]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10714,7 +10892,7 @@ func (x *ListRedPacketsRequest) String() string {
|
||||
func (*ListRedPacketsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ListRedPacketsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[119]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[121]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10727,7 +10905,7 @@ func (x *ListRedPacketsRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ListRedPacketsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ListRedPacketsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{119}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{121}
|
||||
}
|
||||
|
||||
func (x *ListRedPacketsRequest) GetRequestId() string {
|
||||
@ -10825,7 +11003,7 @@ type ListRedPacketsResponse struct {
|
||||
|
||||
func (x *ListRedPacketsResponse) Reset() {
|
||||
*x = ListRedPacketsResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[120]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[122]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10837,7 +11015,7 @@ func (x *ListRedPacketsResponse) String() string {
|
||||
func (*ListRedPacketsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ListRedPacketsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[120]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[122]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10850,7 +11028,7 @@ func (x *ListRedPacketsResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ListRedPacketsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ListRedPacketsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{120}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{122}
|
||||
}
|
||||
|
||||
func (x *ListRedPacketsResponse) GetPackets() []*RedPacket {
|
||||
@ -10887,7 +11065,7 @@ type GetRedPacketRequest struct {
|
||||
|
||||
func (x *GetRedPacketRequest) Reset() {
|
||||
*x = GetRedPacketRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[121]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[123]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10899,7 +11077,7 @@ func (x *GetRedPacketRequest) String() string {
|
||||
func (*GetRedPacketRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetRedPacketRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[121]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[123]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10912,7 +11090,7 @@ func (x *GetRedPacketRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetRedPacketRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetRedPacketRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{121}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{123}
|
||||
}
|
||||
|
||||
func (x *GetRedPacketRequest) GetRequestId() string {
|
||||
@ -10960,7 +11138,7 @@ type GetRedPacketResponse struct {
|
||||
|
||||
func (x *GetRedPacketResponse) Reset() {
|
||||
*x = GetRedPacketResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[122]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[124]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -10972,7 +11150,7 @@ func (x *GetRedPacketResponse) String() string {
|
||||
func (*GetRedPacketResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetRedPacketResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[122]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[124]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -10985,7 +11163,7 @@ func (x *GetRedPacketResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use GetRedPacketResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetRedPacketResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{122}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{124}
|
||||
}
|
||||
|
||||
func (x *GetRedPacketResponse) GetPacket() *RedPacket {
|
||||
@ -11013,7 +11191,7 @@ type ExpireRedPacketsRequest struct {
|
||||
|
||||
func (x *ExpireRedPacketsRequest) Reset() {
|
||||
*x = ExpireRedPacketsRequest{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[123]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[125]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -11025,7 +11203,7 @@ func (x *ExpireRedPacketsRequest) String() string {
|
||||
func (*ExpireRedPacketsRequest) ProtoMessage() {}
|
||||
|
||||
func (x *ExpireRedPacketsRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[123]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[125]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -11038,7 +11216,7 @@ func (x *ExpireRedPacketsRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ExpireRedPacketsRequest.ProtoReflect.Descriptor instead.
|
||||
func (*ExpireRedPacketsRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{123}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{125}
|
||||
}
|
||||
|
||||
func (x *ExpireRedPacketsRequest) GetRequestId() string {
|
||||
@ -11073,7 +11251,7 @@ type ExpireRedPacketsResponse struct {
|
||||
|
||||
func (x *ExpireRedPacketsResponse) Reset() {
|
||||
*x = ExpireRedPacketsResponse{}
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[124]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[126]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -11085,7 +11263,7 @@ func (x *ExpireRedPacketsResponse) String() string {
|
||||
func (*ExpireRedPacketsResponse) ProtoMessage() {}
|
||||
|
||||
func (x *ExpireRedPacketsResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[124]
|
||||
mi := &file_proto_wallet_v1_wallet_proto_msgTypes[126]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -11098,7 +11276,7 @@ func (x *ExpireRedPacketsResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use ExpireRedPacketsResponse.ProtoReflect.Descriptor instead.
|
||||
func (*ExpireRedPacketsResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{124}
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescGZIP(), []int{126}
|
||||
}
|
||||
|
||||
func (x *ExpireRedPacketsResponse) GetExpiredCount() int32 {
|
||||
@ -12117,6 +12295,22 @@ const file_proto_wallet_v1_wallet_proto_rawDesc = "" +
|
||||
"\x0etransaction_id\x18\x01 \x01(\tR\rtransactionId\x127\n" +
|
||||
"\abalance\x18\x02 \x01(\v2\x1d.hyapp.wallet.v1.AssetBalanceR\abalance\x12\x16\n" +
|
||||
"\x06amount\x18\x03 \x01(\x03R\x06amount\x12\"\n" +
|
||||
"\rgranted_at_ms\x18\x04 \x01(\x03R\vgrantedAtMs\"\x92\x02\n" +
|
||||
"\x1cCreditLuckyGiftRewardRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
"command_id\x18\x01 \x01(\tR\tcommandId\x12\x19\n" +
|
||||
"\bapp_code\x18\x02 \x01(\tR\aappCode\x12$\n" +
|
||||
"\x0etarget_user_id\x18\x03 \x01(\x03R\ftargetUserId\x12\x16\n" +
|
||||
"\x06amount\x18\x04 \x01(\x03R\x06amount\x12\x17\n" +
|
||||
"\adraw_id\x18\x05 \x01(\tR\x06drawId\x12\x17\n" +
|
||||
"\aroom_id\x18\x06 \x01(\tR\x06roomId\x12\x17\n" +
|
||||
"\agift_id\x18\a \x01(\tR\x06giftId\x12\x17\n" +
|
||||
"\apool_id\x18\b \x01(\tR\x06poolId\x12\x16\n" +
|
||||
"\x06reason\x18\t \x01(\tR\x06reason\"\xbb\x01\n" +
|
||||
"\x1dCreditLuckyGiftRewardResponse\x12%\n" +
|
||||
"\x0etransaction_id\x18\x01 \x01(\tR\rtransactionId\x127\n" +
|
||||
"\abalance\x18\x02 \x01(\v2\x1d.hyapp.wallet.v1.AssetBalanceR\abalance\x12\x16\n" +
|
||||
"\x06amount\x18\x03 \x01(\x03R\x06amount\x12\"\n" +
|
||||
"\rgranted_at_ms\x18\x04 \x01(\x03R\vgrantedAtMs\"\x9a\x03\n" +
|
||||
"\x1aApplyGameCoinChangeRequest\x12\x1d\n" +
|
||||
"\n" +
|
||||
@ -12280,7 +12474,7 @@ const file_proto_wallet_v1_wallet_proto_rawDesc = "" +
|
||||
"\x18ExpireRedPacketsResponse\x12#\n" +
|
||||
"\rexpired_count\x18\x01 \x01(\x05R\fexpiredCount\x12'\n" +
|
||||
"\x0frefunded_amount\x18\x02 \x01(\x03R\x0erefundedAmount\x12$\n" +
|
||||
"\x0eserver_time_ms\x18\x03 \x01(\x03R\fserverTimeMs2\x86-\n" +
|
||||
"\x0eserver_time_ms\x18\x03 \x01(\x03R\fserverTimeMs2\xfe-\n" +
|
||||
"\rWalletService\x12R\n" +
|
||||
"\tDebitGift\x12!.hyapp.wallet.v1.DebitGiftRequest\x1a\".hyapp.wallet.v1.DebitGiftResponse\x12X\n" +
|
||||
"\vGetBalances\x12#.hyapp.wallet.v1.GetBalancesRequest\x1a$.hyapp.wallet.v1.GetBalancesResponse\x12g\n" +
|
||||
@ -12327,7 +12521,8 @@ const file_proto_wallet_v1_wallet_proto_rawDesc = "" +
|
||||
"\bGrantVip\x12 .hyapp.wallet.v1.GrantVipRequest\x1a!.hyapp.wallet.v1.GrantVipResponse\x12m\n" +
|
||||
"\x12ListAdminVipLevels\x12*.hyapp.wallet.v1.ListAdminVipLevelsRequest\x1a+.hyapp.wallet.v1.ListAdminVipLevelsResponse\x12s\n" +
|
||||
"\x14UpdateAdminVipLevels\x12,.hyapp.wallet.v1.UpdateAdminVipLevelsRequest\x1a-.hyapp.wallet.v1.UpdateAdminVipLevelsResponse\x12g\n" +
|
||||
"\x10CreditTaskReward\x12(.hyapp.wallet.v1.CreditTaskRewardRequest\x1a).hyapp.wallet.v1.CreditTaskRewardResponse\x12p\n" +
|
||||
"\x10CreditTaskReward\x12(.hyapp.wallet.v1.CreditTaskRewardRequest\x1a).hyapp.wallet.v1.CreditTaskRewardResponse\x12v\n" +
|
||||
"\x15CreditLuckyGiftReward\x12-.hyapp.wallet.v1.CreditLuckyGiftRewardRequest\x1a..hyapp.wallet.v1.CreditLuckyGiftRewardResponse\x12p\n" +
|
||||
"\x13ApplyGameCoinChange\x12+.hyapp.wallet.v1.ApplyGameCoinChangeRequest\x1a,.hyapp.wallet.v1.ApplyGameCoinChangeResponse\x12m\n" +
|
||||
"\x12GetRedPacketConfig\x12*.hyapp.wallet.v1.GetRedPacketConfigRequest\x1a+.hyapp.wallet.v1.GetRedPacketConfigResponse\x12v\n" +
|
||||
"\x15UpdateRedPacketConfig\x12-.hyapp.wallet.v1.UpdateRedPacketConfigRequest\x1a..hyapp.wallet.v1.UpdateRedPacketConfigResponse\x12d\n" +
|
||||
@ -12349,7 +12544,7 @@ func file_proto_wallet_v1_wallet_proto_rawDescGZIP() []byte {
|
||||
return file_proto_wallet_v1_wallet_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_wallet_v1_wallet_proto_msgTypes = make([]protoimpl.MessageInfo, 125)
|
||||
var file_proto_wallet_v1_wallet_proto_msgTypes = make([]protoimpl.MessageInfo, 127)
|
||||
var file_proto_wallet_v1_wallet_proto_goTypes = []any{
|
||||
(*DebitGiftRequest)(nil), // 0: hyapp.wallet.v1.DebitGiftRequest
|
||||
(*DebitGiftResponse)(nil), // 1: hyapp.wallet.v1.DebitGiftResponse
|
||||
@ -12457,25 +12652,27 @@ var file_proto_wallet_v1_wallet_proto_goTypes = []any{
|
||||
(*UpdateAdminVipLevelsResponse)(nil), // 103: hyapp.wallet.v1.UpdateAdminVipLevelsResponse
|
||||
(*CreditTaskRewardRequest)(nil), // 104: hyapp.wallet.v1.CreditTaskRewardRequest
|
||||
(*CreditTaskRewardResponse)(nil), // 105: hyapp.wallet.v1.CreditTaskRewardResponse
|
||||
(*ApplyGameCoinChangeRequest)(nil), // 106: hyapp.wallet.v1.ApplyGameCoinChangeRequest
|
||||
(*ApplyGameCoinChangeResponse)(nil), // 107: hyapp.wallet.v1.ApplyGameCoinChangeResponse
|
||||
(*RedPacketConfig)(nil), // 108: hyapp.wallet.v1.RedPacketConfig
|
||||
(*RedPacketClaim)(nil), // 109: hyapp.wallet.v1.RedPacketClaim
|
||||
(*RedPacket)(nil), // 110: hyapp.wallet.v1.RedPacket
|
||||
(*GetRedPacketConfigRequest)(nil), // 111: hyapp.wallet.v1.GetRedPacketConfigRequest
|
||||
(*GetRedPacketConfigResponse)(nil), // 112: hyapp.wallet.v1.GetRedPacketConfigResponse
|
||||
(*UpdateRedPacketConfigRequest)(nil), // 113: hyapp.wallet.v1.UpdateRedPacketConfigRequest
|
||||
(*UpdateRedPacketConfigResponse)(nil), // 114: hyapp.wallet.v1.UpdateRedPacketConfigResponse
|
||||
(*CreateRedPacketRequest)(nil), // 115: hyapp.wallet.v1.CreateRedPacketRequest
|
||||
(*CreateRedPacketResponse)(nil), // 116: hyapp.wallet.v1.CreateRedPacketResponse
|
||||
(*ClaimRedPacketRequest)(nil), // 117: hyapp.wallet.v1.ClaimRedPacketRequest
|
||||
(*ClaimRedPacketResponse)(nil), // 118: hyapp.wallet.v1.ClaimRedPacketResponse
|
||||
(*ListRedPacketsRequest)(nil), // 119: hyapp.wallet.v1.ListRedPacketsRequest
|
||||
(*ListRedPacketsResponse)(nil), // 120: hyapp.wallet.v1.ListRedPacketsResponse
|
||||
(*GetRedPacketRequest)(nil), // 121: hyapp.wallet.v1.GetRedPacketRequest
|
||||
(*GetRedPacketResponse)(nil), // 122: hyapp.wallet.v1.GetRedPacketResponse
|
||||
(*ExpireRedPacketsRequest)(nil), // 123: hyapp.wallet.v1.ExpireRedPacketsRequest
|
||||
(*ExpireRedPacketsResponse)(nil), // 124: hyapp.wallet.v1.ExpireRedPacketsResponse
|
||||
(*CreditLuckyGiftRewardRequest)(nil), // 106: hyapp.wallet.v1.CreditLuckyGiftRewardRequest
|
||||
(*CreditLuckyGiftRewardResponse)(nil), // 107: hyapp.wallet.v1.CreditLuckyGiftRewardResponse
|
||||
(*ApplyGameCoinChangeRequest)(nil), // 108: hyapp.wallet.v1.ApplyGameCoinChangeRequest
|
||||
(*ApplyGameCoinChangeResponse)(nil), // 109: hyapp.wallet.v1.ApplyGameCoinChangeResponse
|
||||
(*RedPacketConfig)(nil), // 110: hyapp.wallet.v1.RedPacketConfig
|
||||
(*RedPacketClaim)(nil), // 111: hyapp.wallet.v1.RedPacketClaim
|
||||
(*RedPacket)(nil), // 112: hyapp.wallet.v1.RedPacket
|
||||
(*GetRedPacketConfigRequest)(nil), // 113: hyapp.wallet.v1.GetRedPacketConfigRequest
|
||||
(*GetRedPacketConfigResponse)(nil), // 114: hyapp.wallet.v1.GetRedPacketConfigResponse
|
||||
(*UpdateRedPacketConfigRequest)(nil), // 115: hyapp.wallet.v1.UpdateRedPacketConfigRequest
|
||||
(*UpdateRedPacketConfigResponse)(nil), // 116: hyapp.wallet.v1.UpdateRedPacketConfigResponse
|
||||
(*CreateRedPacketRequest)(nil), // 117: hyapp.wallet.v1.CreateRedPacketRequest
|
||||
(*CreateRedPacketResponse)(nil), // 118: hyapp.wallet.v1.CreateRedPacketResponse
|
||||
(*ClaimRedPacketRequest)(nil), // 119: hyapp.wallet.v1.ClaimRedPacketRequest
|
||||
(*ClaimRedPacketResponse)(nil), // 120: hyapp.wallet.v1.ClaimRedPacketResponse
|
||||
(*ListRedPacketsRequest)(nil), // 121: hyapp.wallet.v1.ListRedPacketsRequest
|
||||
(*ListRedPacketsResponse)(nil), // 122: hyapp.wallet.v1.ListRedPacketsResponse
|
||||
(*GetRedPacketRequest)(nil), // 123: hyapp.wallet.v1.GetRedPacketRequest
|
||||
(*GetRedPacketResponse)(nil), // 124: hyapp.wallet.v1.GetRedPacketResponse
|
||||
(*ExpireRedPacketsRequest)(nil), // 125: hyapp.wallet.v1.ExpireRedPacketsRequest
|
||||
(*ExpireRedPacketsResponse)(nil), // 126: hyapp.wallet.v1.ExpireRedPacketsResponse
|
||||
}
|
||||
var file_proto_wallet_v1_wallet_proto_depIdxs = []int32{
|
||||
2, // 0: hyapp.wallet.v1.GetBalancesResponse.balances:type_name -> hyapp.wallet.v1.AssetBalance
|
||||
@ -12527,126 +12724,129 @@ var file_proto_wallet_v1_wallet_proto_depIdxs = []int32{
|
||||
99, // 46: hyapp.wallet.v1.UpdateAdminVipLevelsRequest.levels:type_name -> hyapp.wallet.v1.AdminVipLevelInput
|
||||
89, // 47: hyapp.wallet.v1.UpdateAdminVipLevelsResponse.levels:type_name -> hyapp.wallet.v1.VipLevel
|
||||
2, // 48: hyapp.wallet.v1.CreditTaskRewardResponse.balance:type_name -> hyapp.wallet.v1.AssetBalance
|
||||
109, // 49: hyapp.wallet.v1.RedPacket.claims:type_name -> hyapp.wallet.v1.RedPacketClaim
|
||||
108, // 50: hyapp.wallet.v1.GetRedPacketConfigResponse.config:type_name -> hyapp.wallet.v1.RedPacketConfig
|
||||
108, // 51: hyapp.wallet.v1.UpdateRedPacketConfigResponse.config:type_name -> hyapp.wallet.v1.RedPacketConfig
|
||||
110, // 52: hyapp.wallet.v1.CreateRedPacketResponse.packet:type_name -> hyapp.wallet.v1.RedPacket
|
||||
109, // 53: hyapp.wallet.v1.ClaimRedPacketResponse.claim:type_name -> hyapp.wallet.v1.RedPacketClaim
|
||||
110, // 54: hyapp.wallet.v1.ListRedPacketsResponse.packets:type_name -> hyapp.wallet.v1.RedPacket
|
||||
110, // 55: hyapp.wallet.v1.GetRedPacketResponse.packet:type_name -> hyapp.wallet.v1.RedPacket
|
||||
0, // 56: hyapp.wallet.v1.WalletService.DebitGift:input_type -> hyapp.wallet.v1.DebitGiftRequest
|
||||
3, // 57: hyapp.wallet.v1.WalletService.GetBalances:input_type -> hyapp.wallet.v1.GetBalancesRequest
|
||||
5, // 58: hyapp.wallet.v1.WalletService.AdminCreditAsset:input_type -> hyapp.wallet.v1.AdminCreditAssetRequest
|
||||
7, // 59: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:input_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockRequest
|
||||
9, // 60: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:input_type -> hyapp.wallet.v1.TransferCoinFromSellerRequest
|
||||
20, // 61: hyapp.wallet.v1.WalletService.ListResources:input_type -> hyapp.wallet.v1.ListResourcesRequest
|
||||
22, // 62: hyapp.wallet.v1.WalletService.GetResource:input_type -> hyapp.wallet.v1.GetResourceRequest
|
||||
24, // 63: hyapp.wallet.v1.WalletService.CreateResource:input_type -> hyapp.wallet.v1.CreateResourceRequest
|
||||
25, // 64: hyapp.wallet.v1.WalletService.UpdateResource:input_type -> hyapp.wallet.v1.UpdateResourceRequest
|
||||
26, // 65: hyapp.wallet.v1.WalletService.SetResourceStatus:input_type -> hyapp.wallet.v1.SetResourceStatusRequest
|
||||
28, // 66: hyapp.wallet.v1.WalletService.ListResourceGroups:input_type -> hyapp.wallet.v1.ListResourceGroupsRequest
|
||||
30, // 67: hyapp.wallet.v1.WalletService.GetResourceGroup:input_type -> hyapp.wallet.v1.GetResourceGroupRequest
|
||||
32, // 68: hyapp.wallet.v1.WalletService.CreateResourceGroup:input_type -> hyapp.wallet.v1.CreateResourceGroupRequest
|
||||
33, // 69: hyapp.wallet.v1.WalletService.UpdateResourceGroup:input_type -> hyapp.wallet.v1.UpdateResourceGroupRequest
|
||||
34, // 70: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:input_type -> hyapp.wallet.v1.SetResourceGroupStatusRequest
|
||||
36, // 71: hyapp.wallet.v1.WalletService.ListGiftConfigs:input_type -> hyapp.wallet.v1.ListGiftConfigsRequest
|
||||
38, // 72: hyapp.wallet.v1.WalletService.ListGiftTypeConfigs:input_type -> hyapp.wallet.v1.ListGiftTypeConfigsRequest
|
||||
42, // 73: hyapp.wallet.v1.WalletService.CreateGiftConfig:input_type -> hyapp.wallet.v1.CreateGiftConfigRequest
|
||||
43, // 74: hyapp.wallet.v1.WalletService.UpdateGiftConfig:input_type -> hyapp.wallet.v1.UpdateGiftConfigRequest
|
||||
44, // 75: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:input_type -> hyapp.wallet.v1.SetGiftConfigStatusRequest
|
||||
40, // 76: hyapp.wallet.v1.WalletService.UpsertGiftTypeConfig:input_type -> hyapp.wallet.v1.UpsertGiftTypeConfigRequest
|
||||
46, // 77: hyapp.wallet.v1.WalletService.GrantResource:input_type -> hyapp.wallet.v1.GrantResourceRequest
|
||||
47, // 78: hyapp.wallet.v1.WalletService.GrantResourceGroup:input_type -> hyapp.wallet.v1.GrantResourceGroupRequest
|
||||
49, // 79: hyapp.wallet.v1.WalletService.ListUserResources:input_type -> hyapp.wallet.v1.ListUserResourcesRequest
|
||||
51, // 80: hyapp.wallet.v1.WalletService.EquipUserResource:input_type -> hyapp.wallet.v1.EquipUserResourceRequest
|
||||
53, // 81: hyapp.wallet.v1.WalletService.ListResourceGrants:input_type -> hyapp.wallet.v1.ListResourceGrantsRequest
|
||||
56, // 82: hyapp.wallet.v1.WalletService.ListRechargeBills:input_type -> hyapp.wallet.v1.ListRechargeBillsRequest
|
||||
59, // 83: hyapp.wallet.v1.WalletService.GetWalletOverview:input_type -> hyapp.wallet.v1.GetWalletOverviewRequest
|
||||
62, // 84: hyapp.wallet.v1.WalletService.GetWalletValueSummary:input_type -> hyapp.wallet.v1.GetWalletValueSummaryRequest
|
||||
65, // 85: hyapp.wallet.v1.WalletService.GetUserGiftWall:input_type -> hyapp.wallet.v1.GetUserGiftWallRequest
|
||||
68, // 86: hyapp.wallet.v1.WalletService.ListRechargeProducts:input_type -> hyapp.wallet.v1.ListRechargeProductsRequest
|
||||
70, // 87: hyapp.wallet.v1.WalletService.ConfirmGooglePayment:input_type -> hyapp.wallet.v1.ConfirmGooglePaymentRequest
|
||||
72, // 88: hyapp.wallet.v1.WalletService.ListAdminRechargeProducts:input_type -> hyapp.wallet.v1.ListAdminRechargeProductsRequest
|
||||
74, // 89: hyapp.wallet.v1.WalletService.CreateRechargeProduct:input_type -> hyapp.wallet.v1.CreateRechargeProductRequest
|
||||
75, // 90: hyapp.wallet.v1.WalletService.UpdateRechargeProduct:input_type -> hyapp.wallet.v1.UpdateRechargeProductRequest
|
||||
76, // 91: hyapp.wallet.v1.WalletService.DeleteRechargeProduct:input_type -> hyapp.wallet.v1.DeleteRechargeProductRequest
|
||||
80, // 92: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:input_type -> hyapp.wallet.v1.GetDiamondExchangeConfigRequest
|
||||
83, // 93: hyapp.wallet.v1.WalletService.ListWalletTransactions:input_type -> hyapp.wallet.v1.ListWalletTransactionsRequest
|
||||
86, // 94: hyapp.wallet.v1.WalletService.ApplyWithdrawal:input_type -> hyapp.wallet.v1.ApplyWithdrawalRequest
|
||||
91, // 95: hyapp.wallet.v1.WalletService.ListVipPackages:input_type -> hyapp.wallet.v1.ListVipPackagesRequest
|
||||
93, // 96: hyapp.wallet.v1.WalletService.GetMyVip:input_type -> hyapp.wallet.v1.GetMyVipRequest
|
||||
95, // 97: hyapp.wallet.v1.WalletService.PurchaseVip:input_type -> hyapp.wallet.v1.PurchaseVipRequest
|
||||
97, // 98: hyapp.wallet.v1.WalletService.GrantVip:input_type -> hyapp.wallet.v1.GrantVipRequest
|
||||
100, // 99: hyapp.wallet.v1.WalletService.ListAdminVipLevels:input_type -> hyapp.wallet.v1.ListAdminVipLevelsRequest
|
||||
102, // 100: hyapp.wallet.v1.WalletService.UpdateAdminVipLevels:input_type -> hyapp.wallet.v1.UpdateAdminVipLevelsRequest
|
||||
104, // 101: hyapp.wallet.v1.WalletService.CreditTaskReward:input_type -> hyapp.wallet.v1.CreditTaskRewardRequest
|
||||
106, // 102: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:input_type -> hyapp.wallet.v1.ApplyGameCoinChangeRequest
|
||||
111, // 103: hyapp.wallet.v1.WalletService.GetRedPacketConfig:input_type -> hyapp.wallet.v1.GetRedPacketConfigRequest
|
||||
113, // 104: hyapp.wallet.v1.WalletService.UpdateRedPacketConfig:input_type -> hyapp.wallet.v1.UpdateRedPacketConfigRequest
|
||||
115, // 105: hyapp.wallet.v1.WalletService.CreateRedPacket:input_type -> hyapp.wallet.v1.CreateRedPacketRequest
|
||||
117, // 106: hyapp.wallet.v1.WalletService.ClaimRedPacket:input_type -> hyapp.wallet.v1.ClaimRedPacketRequest
|
||||
119, // 107: hyapp.wallet.v1.WalletService.ListRedPackets:input_type -> hyapp.wallet.v1.ListRedPacketsRequest
|
||||
121, // 108: hyapp.wallet.v1.WalletService.GetRedPacket:input_type -> hyapp.wallet.v1.GetRedPacketRequest
|
||||
123, // 109: hyapp.wallet.v1.WalletService.ExpireRedPackets:input_type -> hyapp.wallet.v1.ExpireRedPacketsRequest
|
||||
1, // 110: hyapp.wallet.v1.WalletService.DebitGift:output_type -> hyapp.wallet.v1.DebitGiftResponse
|
||||
4, // 111: hyapp.wallet.v1.WalletService.GetBalances:output_type -> hyapp.wallet.v1.GetBalancesResponse
|
||||
6, // 112: hyapp.wallet.v1.WalletService.AdminCreditAsset:output_type -> hyapp.wallet.v1.AdminCreditAssetResponse
|
||||
8, // 113: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:output_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockResponse
|
||||
10, // 114: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:output_type -> hyapp.wallet.v1.TransferCoinFromSellerResponse
|
||||
21, // 115: hyapp.wallet.v1.WalletService.ListResources:output_type -> hyapp.wallet.v1.ListResourcesResponse
|
||||
23, // 116: hyapp.wallet.v1.WalletService.GetResource:output_type -> hyapp.wallet.v1.GetResourceResponse
|
||||
27, // 117: hyapp.wallet.v1.WalletService.CreateResource:output_type -> hyapp.wallet.v1.ResourceResponse
|
||||
27, // 118: hyapp.wallet.v1.WalletService.UpdateResource:output_type -> hyapp.wallet.v1.ResourceResponse
|
||||
27, // 119: hyapp.wallet.v1.WalletService.SetResourceStatus:output_type -> hyapp.wallet.v1.ResourceResponse
|
||||
29, // 120: hyapp.wallet.v1.WalletService.ListResourceGroups:output_type -> hyapp.wallet.v1.ListResourceGroupsResponse
|
||||
31, // 121: hyapp.wallet.v1.WalletService.GetResourceGroup:output_type -> hyapp.wallet.v1.GetResourceGroupResponse
|
||||
35, // 122: hyapp.wallet.v1.WalletService.CreateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse
|
||||
35, // 123: hyapp.wallet.v1.WalletService.UpdateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse
|
||||
35, // 124: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:output_type -> hyapp.wallet.v1.ResourceGroupResponse
|
||||
37, // 125: hyapp.wallet.v1.WalletService.ListGiftConfigs:output_type -> hyapp.wallet.v1.ListGiftConfigsResponse
|
||||
39, // 126: hyapp.wallet.v1.WalletService.ListGiftTypeConfigs:output_type -> hyapp.wallet.v1.ListGiftTypeConfigsResponse
|
||||
45, // 127: hyapp.wallet.v1.WalletService.CreateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse
|
||||
45, // 128: hyapp.wallet.v1.WalletService.UpdateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse
|
||||
45, // 129: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:output_type -> hyapp.wallet.v1.GiftConfigResponse
|
||||
41, // 130: hyapp.wallet.v1.WalletService.UpsertGiftTypeConfig:output_type -> hyapp.wallet.v1.GiftTypeConfigResponse
|
||||
48, // 131: hyapp.wallet.v1.WalletService.GrantResource:output_type -> hyapp.wallet.v1.ResourceGrantResponse
|
||||
48, // 132: hyapp.wallet.v1.WalletService.GrantResourceGroup:output_type -> hyapp.wallet.v1.ResourceGrantResponse
|
||||
50, // 133: hyapp.wallet.v1.WalletService.ListUserResources:output_type -> hyapp.wallet.v1.ListUserResourcesResponse
|
||||
52, // 134: hyapp.wallet.v1.WalletService.EquipUserResource:output_type -> hyapp.wallet.v1.EquipUserResourceResponse
|
||||
54, // 135: hyapp.wallet.v1.WalletService.ListResourceGrants:output_type -> hyapp.wallet.v1.ListResourceGrantsResponse
|
||||
57, // 136: hyapp.wallet.v1.WalletService.ListRechargeBills:output_type -> hyapp.wallet.v1.ListRechargeBillsResponse
|
||||
60, // 137: hyapp.wallet.v1.WalletService.GetWalletOverview:output_type -> hyapp.wallet.v1.GetWalletOverviewResponse
|
||||
63, // 138: hyapp.wallet.v1.WalletService.GetWalletValueSummary:output_type -> hyapp.wallet.v1.GetWalletValueSummaryResponse
|
||||
66, // 139: hyapp.wallet.v1.WalletService.GetUserGiftWall:output_type -> hyapp.wallet.v1.GetUserGiftWallResponse
|
||||
69, // 140: hyapp.wallet.v1.WalletService.ListRechargeProducts:output_type -> hyapp.wallet.v1.ListRechargeProductsResponse
|
||||
71, // 141: hyapp.wallet.v1.WalletService.ConfirmGooglePayment:output_type -> hyapp.wallet.v1.ConfirmGooglePaymentResponse
|
||||
73, // 142: hyapp.wallet.v1.WalletService.ListAdminRechargeProducts:output_type -> hyapp.wallet.v1.ListAdminRechargeProductsResponse
|
||||
77, // 143: hyapp.wallet.v1.WalletService.CreateRechargeProduct:output_type -> hyapp.wallet.v1.RechargeProductResponse
|
||||
77, // 144: hyapp.wallet.v1.WalletService.UpdateRechargeProduct:output_type -> hyapp.wallet.v1.RechargeProductResponse
|
||||
78, // 145: hyapp.wallet.v1.WalletService.DeleteRechargeProduct:output_type -> hyapp.wallet.v1.DeleteRechargeProductResponse
|
||||
81, // 146: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:output_type -> hyapp.wallet.v1.GetDiamondExchangeConfigResponse
|
||||
84, // 147: hyapp.wallet.v1.WalletService.ListWalletTransactions:output_type -> hyapp.wallet.v1.ListWalletTransactionsResponse
|
||||
87, // 148: hyapp.wallet.v1.WalletService.ApplyWithdrawal:output_type -> hyapp.wallet.v1.ApplyWithdrawalResponse
|
||||
92, // 149: hyapp.wallet.v1.WalletService.ListVipPackages:output_type -> hyapp.wallet.v1.ListVipPackagesResponse
|
||||
94, // 150: hyapp.wallet.v1.WalletService.GetMyVip:output_type -> hyapp.wallet.v1.GetMyVipResponse
|
||||
96, // 151: hyapp.wallet.v1.WalletService.PurchaseVip:output_type -> hyapp.wallet.v1.PurchaseVipResponse
|
||||
98, // 152: hyapp.wallet.v1.WalletService.GrantVip:output_type -> hyapp.wallet.v1.GrantVipResponse
|
||||
101, // 153: hyapp.wallet.v1.WalletService.ListAdminVipLevels:output_type -> hyapp.wallet.v1.ListAdminVipLevelsResponse
|
||||
103, // 154: hyapp.wallet.v1.WalletService.UpdateAdminVipLevels:output_type -> hyapp.wallet.v1.UpdateAdminVipLevelsResponse
|
||||
105, // 155: hyapp.wallet.v1.WalletService.CreditTaskReward:output_type -> hyapp.wallet.v1.CreditTaskRewardResponse
|
||||
107, // 156: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:output_type -> hyapp.wallet.v1.ApplyGameCoinChangeResponse
|
||||
112, // 157: hyapp.wallet.v1.WalletService.GetRedPacketConfig:output_type -> hyapp.wallet.v1.GetRedPacketConfigResponse
|
||||
114, // 158: hyapp.wallet.v1.WalletService.UpdateRedPacketConfig:output_type -> hyapp.wallet.v1.UpdateRedPacketConfigResponse
|
||||
116, // 159: hyapp.wallet.v1.WalletService.CreateRedPacket:output_type -> hyapp.wallet.v1.CreateRedPacketResponse
|
||||
118, // 160: hyapp.wallet.v1.WalletService.ClaimRedPacket:output_type -> hyapp.wallet.v1.ClaimRedPacketResponse
|
||||
120, // 161: hyapp.wallet.v1.WalletService.ListRedPackets:output_type -> hyapp.wallet.v1.ListRedPacketsResponse
|
||||
122, // 162: hyapp.wallet.v1.WalletService.GetRedPacket:output_type -> hyapp.wallet.v1.GetRedPacketResponse
|
||||
124, // 163: hyapp.wallet.v1.WalletService.ExpireRedPackets:output_type -> hyapp.wallet.v1.ExpireRedPacketsResponse
|
||||
110, // [110:164] is the sub-list for method output_type
|
||||
56, // [56:110] is the sub-list for method input_type
|
||||
56, // [56:56] is the sub-list for extension type_name
|
||||
56, // [56:56] is the sub-list for extension extendee
|
||||
0, // [0:56] is the sub-list for field type_name
|
||||
2, // 49: hyapp.wallet.v1.CreditLuckyGiftRewardResponse.balance:type_name -> hyapp.wallet.v1.AssetBalance
|
||||
111, // 50: hyapp.wallet.v1.RedPacket.claims:type_name -> hyapp.wallet.v1.RedPacketClaim
|
||||
110, // 51: hyapp.wallet.v1.GetRedPacketConfigResponse.config:type_name -> hyapp.wallet.v1.RedPacketConfig
|
||||
110, // 52: hyapp.wallet.v1.UpdateRedPacketConfigResponse.config:type_name -> hyapp.wallet.v1.RedPacketConfig
|
||||
112, // 53: hyapp.wallet.v1.CreateRedPacketResponse.packet:type_name -> hyapp.wallet.v1.RedPacket
|
||||
111, // 54: hyapp.wallet.v1.ClaimRedPacketResponse.claim:type_name -> hyapp.wallet.v1.RedPacketClaim
|
||||
112, // 55: hyapp.wallet.v1.ListRedPacketsResponse.packets:type_name -> hyapp.wallet.v1.RedPacket
|
||||
112, // 56: hyapp.wallet.v1.GetRedPacketResponse.packet:type_name -> hyapp.wallet.v1.RedPacket
|
||||
0, // 57: hyapp.wallet.v1.WalletService.DebitGift:input_type -> hyapp.wallet.v1.DebitGiftRequest
|
||||
3, // 58: hyapp.wallet.v1.WalletService.GetBalances:input_type -> hyapp.wallet.v1.GetBalancesRequest
|
||||
5, // 59: hyapp.wallet.v1.WalletService.AdminCreditAsset:input_type -> hyapp.wallet.v1.AdminCreditAssetRequest
|
||||
7, // 60: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:input_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockRequest
|
||||
9, // 61: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:input_type -> hyapp.wallet.v1.TransferCoinFromSellerRequest
|
||||
20, // 62: hyapp.wallet.v1.WalletService.ListResources:input_type -> hyapp.wallet.v1.ListResourcesRequest
|
||||
22, // 63: hyapp.wallet.v1.WalletService.GetResource:input_type -> hyapp.wallet.v1.GetResourceRequest
|
||||
24, // 64: hyapp.wallet.v1.WalletService.CreateResource:input_type -> hyapp.wallet.v1.CreateResourceRequest
|
||||
25, // 65: hyapp.wallet.v1.WalletService.UpdateResource:input_type -> hyapp.wallet.v1.UpdateResourceRequest
|
||||
26, // 66: hyapp.wallet.v1.WalletService.SetResourceStatus:input_type -> hyapp.wallet.v1.SetResourceStatusRequest
|
||||
28, // 67: hyapp.wallet.v1.WalletService.ListResourceGroups:input_type -> hyapp.wallet.v1.ListResourceGroupsRequest
|
||||
30, // 68: hyapp.wallet.v1.WalletService.GetResourceGroup:input_type -> hyapp.wallet.v1.GetResourceGroupRequest
|
||||
32, // 69: hyapp.wallet.v1.WalletService.CreateResourceGroup:input_type -> hyapp.wallet.v1.CreateResourceGroupRequest
|
||||
33, // 70: hyapp.wallet.v1.WalletService.UpdateResourceGroup:input_type -> hyapp.wallet.v1.UpdateResourceGroupRequest
|
||||
34, // 71: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:input_type -> hyapp.wallet.v1.SetResourceGroupStatusRequest
|
||||
36, // 72: hyapp.wallet.v1.WalletService.ListGiftConfigs:input_type -> hyapp.wallet.v1.ListGiftConfigsRequest
|
||||
38, // 73: hyapp.wallet.v1.WalletService.ListGiftTypeConfigs:input_type -> hyapp.wallet.v1.ListGiftTypeConfigsRequest
|
||||
42, // 74: hyapp.wallet.v1.WalletService.CreateGiftConfig:input_type -> hyapp.wallet.v1.CreateGiftConfigRequest
|
||||
43, // 75: hyapp.wallet.v1.WalletService.UpdateGiftConfig:input_type -> hyapp.wallet.v1.UpdateGiftConfigRequest
|
||||
44, // 76: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:input_type -> hyapp.wallet.v1.SetGiftConfigStatusRequest
|
||||
40, // 77: hyapp.wallet.v1.WalletService.UpsertGiftTypeConfig:input_type -> hyapp.wallet.v1.UpsertGiftTypeConfigRequest
|
||||
46, // 78: hyapp.wallet.v1.WalletService.GrantResource:input_type -> hyapp.wallet.v1.GrantResourceRequest
|
||||
47, // 79: hyapp.wallet.v1.WalletService.GrantResourceGroup:input_type -> hyapp.wallet.v1.GrantResourceGroupRequest
|
||||
49, // 80: hyapp.wallet.v1.WalletService.ListUserResources:input_type -> hyapp.wallet.v1.ListUserResourcesRequest
|
||||
51, // 81: hyapp.wallet.v1.WalletService.EquipUserResource:input_type -> hyapp.wallet.v1.EquipUserResourceRequest
|
||||
53, // 82: hyapp.wallet.v1.WalletService.ListResourceGrants:input_type -> hyapp.wallet.v1.ListResourceGrantsRequest
|
||||
56, // 83: hyapp.wallet.v1.WalletService.ListRechargeBills:input_type -> hyapp.wallet.v1.ListRechargeBillsRequest
|
||||
59, // 84: hyapp.wallet.v1.WalletService.GetWalletOverview:input_type -> hyapp.wallet.v1.GetWalletOverviewRequest
|
||||
62, // 85: hyapp.wallet.v1.WalletService.GetWalletValueSummary:input_type -> hyapp.wallet.v1.GetWalletValueSummaryRequest
|
||||
65, // 86: hyapp.wallet.v1.WalletService.GetUserGiftWall:input_type -> hyapp.wallet.v1.GetUserGiftWallRequest
|
||||
68, // 87: hyapp.wallet.v1.WalletService.ListRechargeProducts:input_type -> hyapp.wallet.v1.ListRechargeProductsRequest
|
||||
70, // 88: hyapp.wallet.v1.WalletService.ConfirmGooglePayment:input_type -> hyapp.wallet.v1.ConfirmGooglePaymentRequest
|
||||
72, // 89: hyapp.wallet.v1.WalletService.ListAdminRechargeProducts:input_type -> hyapp.wallet.v1.ListAdminRechargeProductsRequest
|
||||
74, // 90: hyapp.wallet.v1.WalletService.CreateRechargeProduct:input_type -> hyapp.wallet.v1.CreateRechargeProductRequest
|
||||
75, // 91: hyapp.wallet.v1.WalletService.UpdateRechargeProduct:input_type -> hyapp.wallet.v1.UpdateRechargeProductRequest
|
||||
76, // 92: hyapp.wallet.v1.WalletService.DeleteRechargeProduct:input_type -> hyapp.wallet.v1.DeleteRechargeProductRequest
|
||||
80, // 93: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:input_type -> hyapp.wallet.v1.GetDiamondExchangeConfigRequest
|
||||
83, // 94: hyapp.wallet.v1.WalletService.ListWalletTransactions:input_type -> hyapp.wallet.v1.ListWalletTransactionsRequest
|
||||
86, // 95: hyapp.wallet.v1.WalletService.ApplyWithdrawal:input_type -> hyapp.wallet.v1.ApplyWithdrawalRequest
|
||||
91, // 96: hyapp.wallet.v1.WalletService.ListVipPackages:input_type -> hyapp.wallet.v1.ListVipPackagesRequest
|
||||
93, // 97: hyapp.wallet.v1.WalletService.GetMyVip:input_type -> hyapp.wallet.v1.GetMyVipRequest
|
||||
95, // 98: hyapp.wallet.v1.WalletService.PurchaseVip:input_type -> hyapp.wallet.v1.PurchaseVipRequest
|
||||
97, // 99: hyapp.wallet.v1.WalletService.GrantVip:input_type -> hyapp.wallet.v1.GrantVipRequest
|
||||
100, // 100: hyapp.wallet.v1.WalletService.ListAdminVipLevels:input_type -> hyapp.wallet.v1.ListAdminVipLevelsRequest
|
||||
102, // 101: hyapp.wallet.v1.WalletService.UpdateAdminVipLevels:input_type -> hyapp.wallet.v1.UpdateAdminVipLevelsRequest
|
||||
104, // 102: hyapp.wallet.v1.WalletService.CreditTaskReward:input_type -> hyapp.wallet.v1.CreditTaskRewardRequest
|
||||
106, // 103: hyapp.wallet.v1.WalletService.CreditLuckyGiftReward:input_type -> hyapp.wallet.v1.CreditLuckyGiftRewardRequest
|
||||
108, // 104: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:input_type -> hyapp.wallet.v1.ApplyGameCoinChangeRequest
|
||||
113, // 105: hyapp.wallet.v1.WalletService.GetRedPacketConfig:input_type -> hyapp.wallet.v1.GetRedPacketConfigRequest
|
||||
115, // 106: hyapp.wallet.v1.WalletService.UpdateRedPacketConfig:input_type -> hyapp.wallet.v1.UpdateRedPacketConfigRequest
|
||||
117, // 107: hyapp.wallet.v1.WalletService.CreateRedPacket:input_type -> hyapp.wallet.v1.CreateRedPacketRequest
|
||||
119, // 108: hyapp.wallet.v1.WalletService.ClaimRedPacket:input_type -> hyapp.wallet.v1.ClaimRedPacketRequest
|
||||
121, // 109: hyapp.wallet.v1.WalletService.ListRedPackets:input_type -> hyapp.wallet.v1.ListRedPacketsRequest
|
||||
123, // 110: hyapp.wallet.v1.WalletService.GetRedPacket:input_type -> hyapp.wallet.v1.GetRedPacketRequest
|
||||
125, // 111: hyapp.wallet.v1.WalletService.ExpireRedPackets:input_type -> hyapp.wallet.v1.ExpireRedPacketsRequest
|
||||
1, // 112: hyapp.wallet.v1.WalletService.DebitGift:output_type -> hyapp.wallet.v1.DebitGiftResponse
|
||||
4, // 113: hyapp.wallet.v1.WalletService.GetBalances:output_type -> hyapp.wallet.v1.GetBalancesResponse
|
||||
6, // 114: hyapp.wallet.v1.WalletService.AdminCreditAsset:output_type -> hyapp.wallet.v1.AdminCreditAssetResponse
|
||||
8, // 115: hyapp.wallet.v1.WalletService.AdminCreditCoinSellerStock:output_type -> hyapp.wallet.v1.AdminCreditCoinSellerStockResponse
|
||||
10, // 116: hyapp.wallet.v1.WalletService.TransferCoinFromSeller:output_type -> hyapp.wallet.v1.TransferCoinFromSellerResponse
|
||||
21, // 117: hyapp.wallet.v1.WalletService.ListResources:output_type -> hyapp.wallet.v1.ListResourcesResponse
|
||||
23, // 118: hyapp.wallet.v1.WalletService.GetResource:output_type -> hyapp.wallet.v1.GetResourceResponse
|
||||
27, // 119: hyapp.wallet.v1.WalletService.CreateResource:output_type -> hyapp.wallet.v1.ResourceResponse
|
||||
27, // 120: hyapp.wallet.v1.WalletService.UpdateResource:output_type -> hyapp.wallet.v1.ResourceResponse
|
||||
27, // 121: hyapp.wallet.v1.WalletService.SetResourceStatus:output_type -> hyapp.wallet.v1.ResourceResponse
|
||||
29, // 122: hyapp.wallet.v1.WalletService.ListResourceGroups:output_type -> hyapp.wallet.v1.ListResourceGroupsResponse
|
||||
31, // 123: hyapp.wallet.v1.WalletService.GetResourceGroup:output_type -> hyapp.wallet.v1.GetResourceGroupResponse
|
||||
35, // 124: hyapp.wallet.v1.WalletService.CreateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse
|
||||
35, // 125: hyapp.wallet.v1.WalletService.UpdateResourceGroup:output_type -> hyapp.wallet.v1.ResourceGroupResponse
|
||||
35, // 126: hyapp.wallet.v1.WalletService.SetResourceGroupStatus:output_type -> hyapp.wallet.v1.ResourceGroupResponse
|
||||
37, // 127: hyapp.wallet.v1.WalletService.ListGiftConfigs:output_type -> hyapp.wallet.v1.ListGiftConfigsResponse
|
||||
39, // 128: hyapp.wallet.v1.WalletService.ListGiftTypeConfigs:output_type -> hyapp.wallet.v1.ListGiftTypeConfigsResponse
|
||||
45, // 129: hyapp.wallet.v1.WalletService.CreateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse
|
||||
45, // 130: hyapp.wallet.v1.WalletService.UpdateGiftConfig:output_type -> hyapp.wallet.v1.GiftConfigResponse
|
||||
45, // 131: hyapp.wallet.v1.WalletService.SetGiftConfigStatus:output_type -> hyapp.wallet.v1.GiftConfigResponse
|
||||
41, // 132: hyapp.wallet.v1.WalletService.UpsertGiftTypeConfig:output_type -> hyapp.wallet.v1.GiftTypeConfigResponse
|
||||
48, // 133: hyapp.wallet.v1.WalletService.GrantResource:output_type -> hyapp.wallet.v1.ResourceGrantResponse
|
||||
48, // 134: hyapp.wallet.v1.WalletService.GrantResourceGroup:output_type -> hyapp.wallet.v1.ResourceGrantResponse
|
||||
50, // 135: hyapp.wallet.v1.WalletService.ListUserResources:output_type -> hyapp.wallet.v1.ListUserResourcesResponse
|
||||
52, // 136: hyapp.wallet.v1.WalletService.EquipUserResource:output_type -> hyapp.wallet.v1.EquipUserResourceResponse
|
||||
54, // 137: hyapp.wallet.v1.WalletService.ListResourceGrants:output_type -> hyapp.wallet.v1.ListResourceGrantsResponse
|
||||
57, // 138: hyapp.wallet.v1.WalletService.ListRechargeBills:output_type -> hyapp.wallet.v1.ListRechargeBillsResponse
|
||||
60, // 139: hyapp.wallet.v1.WalletService.GetWalletOverview:output_type -> hyapp.wallet.v1.GetWalletOverviewResponse
|
||||
63, // 140: hyapp.wallet.v1.WalletService.GetWalletValueSummary:output_type -> hyapp.wallet.v1.GetWalletValueSummaryResponse
|
||||
66, // 141: hyapp.wallet.v1.WalletService.GetUserGiftWall:output_type -> hyapp.wallet.v1.GetUserGiftWallResponse
|
||||
69, // 142: hyapp.wallet.v1.WalletService.ListRechargeProducts:output_type -> hyapp.wallet.v1.ListRechargeProductsResponse
|
||||
71, // 143: hyapp.wallet.v1.WalletService.ConfirmGooglePayment:output_type -> hyapp.wallet.v1.ConfirmGooglePaymentResponse
|
||||
73, // 144: hyapp.wallet.v1.WalletService.ListAdminRechargeProducts:output_type -> hyapp.wallet.v1.ListAdminRechargeProductsResponse
|
||||
77, // 145: hyapp.wallet.v1.WalletService.CreateRechargeProduct:output_type -> hyapp.wallet.v1.RechargeProductResponse
|
||||
77, // 146: hyapp.wallet.v1.WalletService.UpdateRechargeProduct:output_type -> hyapp.wallet.v1.RechargeProductResponse
|
||||
78, // 147: hyapp.wallet.v1.WalletService.DeleteRechargeProduct:output_type -> hyapp.wallet.v1.DeleteRechargeProductResponse
|
||||
81, // 148: hyapp.wallet.v1.WalletService.GetDiamondExchangeConfig:output_type -> hyapp.wallet.v1.GetDiamondExchangeConfigResponse
|
||||
84, // 149: hyapp.wallet.v1.WalletService.ListWalletTransactions:output_type -> hyapp.wallet.v1.ListWalletTransactionsResponse
|
||||
87, // 150: hyapp.wallet.v1.WalletService.ApplyWithdrawal:output_type -> hyapp.wallet.v1.ApplyWithdrawalResponse
|
||||
92, // 151: hyapp.wallet.v1.WalletService.ListVipPackages:output_type -> hyapp.wallet.v1.ListVipPackagesResponse
|
||||
94, // 152: hyapp.wallet.v1.WalletService.GetMyVip:output_type -> hyapp.wallet.v1.GetMyVipResponse
|
||||
96, // 153: hyapp.wallet.v1.WalletService.PurchaseVip:output_type -> hyapp.wallet.v1.PurchaseVipResponse
|
||||
98, // 154: hyapp.wallet.v1.WalletService.GrantVip:output_type -> hyapp.wallet.v1.GrantVipResponse
|
||||
101, // 155: hyapp.wallet.v1.WalletService.ListAdminVipLevels:output_type -> hyapp.wallet.v1.ListAdminVipLevelsResponse
|
||||
103, // 156: hyapp.wallet.v1.WalletService.UpdateAdminVipLevels:output_type -> hyapp.wallet.v1.UpdateAdminVipLevelsResponse
|
||||
105, // 157: hyapp.wallet.v1.WalletService.CreditTaskReward:output_type -> hyapp.wallet.v1.CreditTaskRewardResponse
|
||||
107, // 158: hyapp.wallet.v1.WalletService.CreditLuckyGiftReward:output_type -> hyapp.wallet.v1.CreditLuckyGiftRewardResponse
|
||||
109, // 159: hyapp.wallet.v1.WalletService.ApplyGameCoinChange:output_type -> hyapp.wallet.v1.ApplyGameCoinChangeResponse
|
||||
114, // 160: hyapp.wallet.v1.WalletService.GetRedPacketConfig:output_type -> hyapp.wallet.v1.GetRedPacketConfigResponse
|
||||
116, // 161: hyapp.wallet.v1.WalletService.UpdateRedPacketConfig:output_type -> hyapp.wallet.v1.UpdateRedPacketConfigResponse
|
||||
118, // 162: hyapp.wallet.v1.WalletService.CreateRedPacket:output_type -> hyapp.wallet.v1.CreateRedPacketResponse
|
||||
120, // 163: hyapp.wallet.v1.WalletService.ClaimRedPacket:output_type -> hyapp.wallet.v1.ClaimRedPacketResponse
|
||||
122, // 164: hyapp.wallet.v1.WalletService.ListRedPackets:output_type -> hyapp.wallet.v1.ListRedPacketsResponse
|
||||
124, // 165: hyapp.wallet.v1.WalletService.GetRedPacket:output_type -> hyapp.wallet.v1.GetRedPacketResponse
|
||||
126, // 166: hyapp.wallet.v1.WalletService.ExpireRedPackets:output_type -> hyapp.wallet.v1.ExpireRedPacketsResponse
|
||||
112, // [112:167] is the sub-list for method output_type
|
||||
57, // [57:112] is the sub-list for method input_type
|
||||
57, // [57:57] is the sub-list for extension type_name
|
||||
57, // [57:57] is the sub-list for extension extendee
|
||||
0, // [0:57] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_wallet_v1_wallet_proto_init() }
|
||||
@ -12662,7 +12862,7 @@ func file_proto_wallet_v1_wallet_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_wallet_v1_wallet_proto_rawDesc), len(file_proto_wallet_v1_wallet_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 125,
|
||||
NumMessages: 127,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@ -1049,6 +1049,27 @@ message CreditTaskRewardResponse {
|
||||
int64 granted_at_ms = 4;
|
||||
}
|
||||
|
||||
// CreditLuckyGiftRewardRequest 是 activity-service 抽奖 outbox 补偿 worker 调用的钱包入账命令。
|
||||
message CreditLuckyGiftRewardRequest {
|
||||
string command_id = 1;
|
||||
string app_code = 2;
|
||||
int64 target_user_id = 3;
|
||||
int64 amount = 4;
|
||||
string draw_id = 5;
|
||||
string room_id = 6;
|
||||
string gift_id = 7;
|
||||
string pool_id = 8;
|
||||
string reason = 9;
|
||||
}
|
||||
|
||||
// CreditLuckyGiftRewardResponse 返回幸运礼物返奖入账流水和用户 COIN 账后余额。
|
||||
message CreditLuckyGiftRewardResponse {
|
||||
string transaction_id = 1;
|
||||
AssetBalance balance = 2;
|
||||
int64 amount = 3;
|
||||
int64 granted_at_ms = 4;
|
||||
}
|
||||
|
||||
// ApplyGameCoinChangeRequest 是 game-service 唯一可以调用的钱包游戏改账入口。
|
||||
message ApplyGameCoinChangeRequest {
|
||||
string request_id = 1;
|
||||
@ -1274,6 +1295,7 @@ service WalletService {
|
||||
rpc ListAdminVipLevels(ListAdminVipLevelsRequest) returns (ListAdminVipLevelsResponse);
|
||||
rpc UpdateAdminVipLevels(UpdateAdminVipLevelsRequest) returns (UpdateAdminVipLevelsResponse);
|
||||
rpc CreditTaskReward(CreditTaskRewardRequest) returns (CreditTaskRewardResponse);
|
||||
rpc CreditLuckyGiftReward(CreditLuckyGiftRewardRequest) returns (CreditLuckyGiftRewardResponse);
|
||||
rpc ApplyGameCoinChange(ApplyGameCoinChangeRequest) returns (ApplyGameCoinChangeResponse);
|
||||
rpc GetRedPacketConfig(GetRedPacketConfigRequest) returns (GetRedPacketConfigResponse);
|
||||
rpc UpdateRedPacketConfig(UpdateRedPacketConfigRequest) returns (UpdateRedPacketConfigResponse);
|
||||
|
||||
@ -65,6 +65,7 @@ const (
|
||||
WalletService_ListAdminVipLevels_FullMethodName = "/hyapp.wallet.v1.WalletService/ListAdminVipLevels"
|
||||
WalletService_UpdateAdminVipLevels_FullMethodName = "/hyapp.wallet.v1.WalletService/UpdateAdminVipLevels"
|
||||
WalletService_CreditTaskReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditTaskReward"
|
||||
WalletService_CreditLuckyGiftReward_FullMethodName = "/hyapp.wallet.v1.WalletService/CreditLuckyGiftReward"
|
||||
WalletService_ApplyGameCoinChange_FullMethodName = "/hyapp.wallet.v1.WalletService/ApplyGameCoinChange"
|
||||
WalletService_GetRedPacketConfig_FullMethodName = "/hyapp.wallet.v1.WalletService/GetRedPacketConfig"
|
||||
WalletService_UpdateRedPacketConfig_FullMethodName = "/hyapp.wallet.v1.WalletService/UpdateRedPacketConfig"
|
||||
@ -127,6 +128,7 @@ type WalletServiceClient interface {
|
||||
ListAdminVipLevels(ctx context.Context, in *ListAdminVipLevelsRequest, opts ...grpc.CallOption) (*ListAdminVipLevelsResponse, error)
|
||||
UpdateAdminVipLevels(ctx context.Context, in *UpdateAdminVipLevelsRequest, opts ...grpc.CallOption) (*UpdateAdminVipLevelsResponse, error)
|
||||
CreditTaskReward(ctx context.Context, in *CreditTaskRewardRequest, opts ...grpc.CallOption) (*CreditTaskRewardResponse, error)
|
||||
CreditLuckyGiftReward(ctx context.Context, in *CreditLuckyGiftRewardRequest, opts ...grpc.CallOption) (*CreditLuckyGiftRewardResponse, error)
|
||||
ApplyGameCoinChange(ctx context.Context, in *ApplyGameCoinChangeRequest, opts ...grpc.CallOption) (*ApplyGameCoinChangeResponse, error)
|
||||
GetRedPacketConfig(ctx context.Context, in *GetRedPacketConfigRequest, opts ...grpc.CallOption) (*GetRedPacketConfigResponse, error)
|
||||
UpdateRedPacketConfig(ctx context.Context, in *UpdateRedPacketConfigRequest, opts ...grpc.CallOption) (*UpdateRedPacketConfigResponse, error)
|
||||
@ -605,6 +607,16 @@ func (c *walletServiceClient) CreditTaskReward(ctx context.Context, in *CreditTa
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) CreditLuckyGiftReward(ctx context.Context, in *CreditLuckyGiftRewardRequest, opts ...grpc.CallOption) (*CreditLuckyGiftRewardResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(CreditLuckyGiftRewardResponse)
|
||||
err := c.cc.Invoke(ctx, WalletService_CreditLuckyGiftReward_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) ApplyGameCoinChange(ctx context.Context, in *ApplyGameCoinChangeRequest, opts ...grpc.CallOption) (*ApplyGameCoinChangeResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ApplyGameCoinChangeResponse)
|
||||
@ -737,6 +749,7 @@ type WalletServiceServer interface {
|
||||
ListAdminVipLevels(context.Context, *ListAdminVipLevelsRequest) (*ListAdminVipLevelsResponse, error)
|
||||
UpdateAdminVipLevels(context.Context, *UpdateAdminVipLevelsRequest) (*UpdateAdminVipLevelsResponse, error)
|
||||
CreditTaskReward(context.Context, *CreditTaskRewardRequest) (*CreditTaskRewardResponse, error)
|
||||
CreditLuckyGiftReward(context.Context, *CreditLuckyGiftRewardRequest) (*CreditLuckyGiftRewardResponse, error)
|
||||
ApplyGameCoinChange(context.Context, *ApplyGameCoinChangeRequest) (*ApplyGameCoinChangeResponse, error)
|
||||
GetRedPacketConfig(context.Context, *GetRedPacketConfigRequest) (*GetRedPacketConfigResponse, error)
|
||||
UpdateRedPacketConfig(context.Context, *UpdateRedPacketConfigRequest) (*UpdateRedPacketConfigResponse, error)
|
||||
@ -893,6 +906,9 @@ func (UnimplementedWalletServiceServer) UpdateAdminVipLevels(context.Context, *U
|
||||
func (UnimplementedWalletServiceServer) CreditTaskReward(context.Context, *CreditTaskRewardRequest) (*CreditTaskRewardResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreditTaskReward not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreditLuckyGiftReward(context.Context, *CreditLuckyGiftRewardRequest) (*CreditLuckyGiftRewardResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method CreditLuckyGiftReward not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ApplyGameCoinChange(context.Context, *ApplyGameCoinChangeRequest) (*ApplyGameCoinChangeResponse, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ApplyGameCoinChange not implemented")
|
||||
}
|
||||
@ -1766,6 +1782,24 @@ func _WalletService_CreditTaskReward_Handler(srv interface{}, ctx context.Contex
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_CreditLuckyGiftReward_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreditLuckyGiftRewardRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WalletServiceServer).CreditLuckyGiftReward(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WalletService_CreditLuckyGiftReward_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WalletServiceServer).CreditLuckyGiftReward(ctx, req.(*CreditLuckyGiftRewardRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_ApplyGameCoinChange_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ApplyGameCoinChangeRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -2101,6 +2135,10 @@ var WalletService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "CreditTaskReward",
|
||||
Handler: _WalletService_CreditTaskReward_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreditLuckyGiftReward",
|
||||
Handler: _WalletService_CreditLuckyGiftReward_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ApplyGameCoinChange",
|
||||
Handler: _WalletService_ApplyGameCoinChange_Handler,
|
||||
|
||||
@ -60,19 +60,14 @@ App 不要展示后台 RTP 数值,不要展示实时概率,不要本地推
|
||||
| --- | --- |
|
||||
| `POST /api/v1/rooms/gift/send` 支持 `pool_id` 入参 | 已有 |
|
||||
| 房间送礼 IM `room_gift_sent` 可携带 `pool_id` | 已有 |
|
||||
| `POST /api/v1/activities/lucky-gifts/check` | 已有 |
|
||||
| `activity-service` 内部 gRPC `CheckLuckyGift` / `ExecuteLuckyGiftDraw` | 已有 |
|
||||
| 后台按 `pool_id` 配置多奖池 | 已有 |
|
||||
| 送礼响应直接返回抽奖结果 `data.lucky_gift` | 已有 |
|
||||
| 房间 IM `lucky_gift_drawn` | 已有 |
|
||||
| 中奖返奖入账并触发 `WalletBalanceChanged` | 已有 |
|
||||
|
||||
Flutter 完整体验还需要后端补齐:
|
||||
|
||||
| 能力 | 建议 |
|
||||
| --- | --- |
|
||||
| App 查询某个奖池是否可抽 | 新增 HTTP `POST /api/v1/activities/lucky-gifts/check` |
|
||||
| 送礼响应直接返回抽奖结果 | 在 `/rooms/gift/send` 成功 `data` 中增加 `lucky_gift` |
|
||||
| 中奖房间表现 | 新增房间 IM `lucky_gift_drawn` |
|
||||
| 返奖到账 | 钱包侧新增幸运礼物返奖入账后继续发 `WalletBalanceChanged` |
|
||||
|
||||
下面文档按最终 Flutter 契约编写;已存在字段可直接对接,标注为“建议新增”的字段需要后端继续落地。
|
||||
简洁版接入清单见 [幸运礼物接口闭环Flutter对接.md](/Users/hy/Documents/hy/hyapp-server/docs/flutter对接/幸运礼物接口闭环Flutter对接.md)。
|
||||
|
||||
## 客户端流程
|
||||
|
||||
@ -585,4 +580,3 @@ Payload 示例:
|
||||
6. 监听房间 IM `room_gift_sent`、`lucky_gift_drawn`,同步其他用户看到的表现。
|
||||
7. 监听 C2C IM `WalletBalanceChanged`,更新金币余额。
|
||||
8. 任意 IM 丢失、页面重进或余额不一致时,重新拉取礼物面板和钱包余额纠正状态。
|
||||
|
||||
|
||||
171
docs/flutter对接/幸运礼物接口闭环Flutter对接.md
Normal file
171
docs/flutter对接/幸运礼物接口闭环Flutter对接.md
Normal file
@ -0,0 +1,171 @@
|
||||
# 幸运礼物 Flutter 对接
|
||||
|
||||
本文只描述 App 需要接入的 HTTP、送礼返回、错误处理和腾讯云 IM 自定义消息。所有接口响应都使用 gateway 业务 envelope:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": "OK",
|
||||
"message": "",
|
||||
"request_id": "req_xxx",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
## 1. 送礼前检查
|
||||
|
||||
`POST /api/v1/activities/lucky-gifts/check`
|
||||
|
||||
请求头:
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `Authorization` | 是 | `Bearer <access_token>` |
|
||||
| `X-App-Code` | 否 | 不传时使用默认 App |
|
||||
|
||||
请求体:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `room_id` | string | 是 | 当前房间 ID |
|
||||
| `gift_id` | string | 是 | 实际送出的礼物 ID,例如 `rose` |
|
||||
| `pool_id` | string | 是 | 幸运礼物奖池 ID,例如 `lucky`、`super_lucky` |
|
||||
|
||||
返回 `data`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `enabled` | bool | 是否可按幸运礼物发送 |
|
||||
| `reason` | string | `enabled`、`not_configured`、`disabled` |
|
||||
| `room_id` | string | 请求房间 ID |
|
||||
| `gift_id` | string | 请求礼物 ID |
|
||||
| `pool_id` | string | 生效奖池 ID |
|
||||
| `gift_price` | int | 单次抽奖价格,金币 |
|
||||
| `rule_version` | int | 后端规则版本 |
|
||||
| `target_rtp_ppm` | int | RTP 目标,ppm |
|
||||
| `experience_pool` | string | `novice`、`intermediate`、`advanced` |
|
||||
|
||||
客户端处理:
|
||||
|
||||
- `enabled=true`:允许用户继续点击送礼。
|
||||
- `enabled=false`:不要走幸运礼物送礼;可降级普通礼物或提示当前不可用。
|
||||
- 检查结果只用于展示和拦截,最终仍以送礼接口为准。
|
||||
|
||||
## 2. 发送礼物
|
||||
|
||||
`POST /api/v1/rooms/gift/send`
|
||||
|
||||
请求体关键字段:
|
||||
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `room_id` | string | 是 | 房间 ID |
|
||||
| `target_user_id` | int/string | 是 | 收礼用户 ID |
|
||||
| `gift_id` | string | 是 | 礼物 ID,例如 `rose` |
|
||||
| `gift_count` | int | 是 | 数量,必须大于 0 |
|
||||
| `pool_id` | string | 幸运礼物必填 | `lucky` 或 `super_lucky` |
|
||||
| `client_sequence` | string | 建议 | 客户端幂等序列 |
|
||||
|
||||
返回 `data.lucky_gift`:
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| `draw_id` | string | 抽奖 ID,客户端去重锚点 |
|
||||
| `command_id` | string | 送礼命令 ID |
|
||||
| `pool_id` | string | 生效奖池 |
|
||||
| `gift_id` | string | 礼物 ID |
|
||||
| `rule_version` | int | 抽奖规则版本 |
|
||||
| `experience_pool` | string | 体验池 |
|
||||
| `selected_tier_id` | string | 命中奖档 |
|
||||
| `multiplier_ppm` | int | 倍率,`2000000` 表示 2 倍 |
|
||||
| `base_reward_coins` | int | RTP 基础返奖 |
|
||||
| `room_atmosphere_reward_coins` | int | 房间气氛池返奖 |
|
||||
| `activity_subsidy_coins` | int | 活动补贴返奖 |
|
||||
| `effective_reward_coins` | int | 用户实际获得金币 |
|
||||
| `reward_status` | string | 初始通常为 `pending`,到账由后端 outbox 补偿 |
|
||||
| `stage_feedback` | bool | 是否阶段反馈,可播放轻量中奖表现 |
|
||||
| `high_multiplier` | bool | 是否高倍 |
|
||||
| `created_at_ms` | int | UTC epoch ms |
|
||||
|
||||
客户端处理:
|
||||
|
||||
- `data.lucky_gift != null`:立即调用 `_applyLuckyGiftResult()`,播放中奖内容和数量 SVGA。
|
||||
- `effective_reward_coins > 0`:展示中奖金额;余额不要本地相加,以 `WalletBalanceChanged` 或余额刷新为准。
|
||||
- `data.lucky_gift == null`:按普通礼物表现处理。
|
||||
|
||||
## 3. 错误处理
|
||||
|
||||
| code | 场景 | 客户端处理 |
|
||||
| --- | --- | --- |
|
||||
| `INVALID_ARGUMENT` | 参数缺失、数量非法、pool_id 缺失 | 停止提交,提示用户重试或刷新礼物面板 |
|
||||
| `UNAUTHENTICATED` | token 失效 | 重新登录 |
|
||||
| `INSUFFICIENT_BALANCE` | 金币不足 | 打开充值入口或提示余额不足 |
|
||||
| `RULE_NOT_ACTIVE` | 幸运礼物规则未启用 | 降级普通礼物或刷新礼物配置 |
|
||||
| `UPSTREAM_ERROR`/`UNAVAILABLE` | 内部服务或 IM/钱包临时不可用 | 不重复扣本地余额;允许用户稍后重试 |
|
||||
| `IDEMPOTENCY_CONFLICT`/`CONFLICT` | 同一客户端命令参数变化 | 重新生成 `client_sequence` 后再提交 |
|
||||
|
||||
送礼失败时后端不会返回 `lucky_gift`,客户端不要播放中奖 UI。送礼成功但返奖到账延迟时,房间 IM 和钱包 IM 会继续补偿。
|
||||
|
||||
## 4. 房间 IM
|
||||
|
||||
腾讯云 IM 群自定义消息:
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| `MsgType` | `TIMCustomElem` |
|
||||
| `Desc` | `lucky_gift_drawn` |
|
||||
| `Ext` | `room_system_message` |
|
||||
| `Data` | JSON 字符串 |
|
||||
|
||||
`Data` 示例:
|
||||
|
||||
```json
|
||||
{
|
||||
"event_type": "lucky_gift_drawn",
|
||||
"event_id": "lucky_gift_drawn:lucky_draw_xxx",
|
||||
"draw_id": "lucky_draw_xxx",
|
||||
"command_id": "cmd_xxx",
|
||||
"pool_id": "super_lucky",
|
||||
"room_id": "room_1",
|
||||
"gift_id": "rose",
|
||||
"gift_count": 1,
|
||||
"user_id": 42,
|
||||
"sender_user_id": 42,
|
||||
"target_user_id": 99,
|
||||
"coin_spent": 100,
|
||||
"multiplier_ppm": 2000000,
|
||||
"effective_reward_coins": 200,
|
||||
"stage_feedback": true,
|
||||
"high_multiplier": false,
|
||||
"created_at_ms": 1760000000000
|
||||
}
|
||||
```
|
||||
|
||||
处理规则:
|
||||
|
||||
- 只处理 `Desc == "lucky_gift_drawn"` 且 `event_type == "lucky_gift_drawn"`。
|
||||
- 用 `event_id` 或 `draw_id` 去重;同一抽奖不要重复播放。
|
||||
- 当前用户已通过 HTTP 送礼响应播放过同一 `draw_id` 时,收到 IM 只更新状态,不重复播放。
|
||||
|
||||
## 5. 钱包余额 IM
|
||||
|
||||
中奖金币到账后,wallet-service 会写 `WalletBalanceChanged`,notice-service 通过腾讯云 IM C2C 投递。
|
||||
|
||||
| 字段 | 值 |
|
||||
| --- | --- |
|
||||
| `MsgType` | `TIMCustomElem` |
|
||||
| `Desc` | `WalletBalanceChanged` |
|
||||
| `Ext` | `wallet_notice` |
|
||||
|
||||
客户端处理:
|
||||
|
||||
- 只处理 `Desc == "WalletBalanceChanged"`。
|
||||
- 用 `event_id` 去重。
|
||||
- 当 `asset_type == "COIN"` 时,用 `available_after` 更新金币余额;字段缺失时调用 `GET /api/v1/wallet/me/balances` 刷新。
|
||||
|
||||
## 6. 接入顺序
|
||||
|
||||
1. 礼物面板拿到 `pool_id` 后调用 check。
|
||||
2. check 可用后调用送礼接口,并把 `pool_id` 放入请求。
|
||||
3. 送礼响应含 `data.lucky_gift` 时立即播放本机中奖 UI。
|
||||
4. 房间内监听 `lucky_gift_drawn`,给其他用户同步中奖 UI。
|
||||
5. 私聊监听 `WalletBalanceChanged`,更新金币余额。
|
||||
@ -18,8 +18,11 @@
|
||||
| 风控计数 | done | user hour/day、device day、room hour、anchor day |
|
||||
| 房间气氛池 | done | 独立预算,不污染基础 RTP |
|
||||
| 活动预算池 | done | 独立补贴,不污染基础 RTP |
|
||||
| 返奖入账 | done | `activity_outbox` worker 调 `wallet-service.CreditLuckyGiftReward`,钱包 outbox 继续触发余额私信 |
|
||||
| 房间中奖 IM | done | `activity_outbox` worker 投递腾讯云 IM 群消息 `lucky_gift_drawn` |
|
||||
| App 检查接口 | done | gateway 暴露 `POST /api/v1/activities/lucky-gifts/check` |
|
||||
|
||||
暂不在 `activity-service` 事务内调用钱包或房间 RPC。抽奖事务只写事实和 `activity_outbox`;后续由 outbox dispatcher 或房间链路消费结果。
|
||||
`activity-service` 抽奖事务内仍不调用钱包、房间 RPC 或腾讯云 IM。抽奖事务只写事实和 `activity_outbox`;事务外由 lucky gift worker 抢占 outbox,先幂等返奖,再投递房间中奖 IM,最后标记 draw 和 outbox 状态。
|
||||
|
||||
## Call Flow
|
||||
|
||||
@ -27,9 +30,12 @@
|
||||
room-service SendGift
|
||||
1. CheckLuckyGift(meta, user_id, room_id, gift_id, pool_id)
|
||||
2. wallet-service 扣费成功
|
||||
3. ExecuteLuckyGiftDraw(command_id, user_id, device_id, room_id, anchor_id, gift_id, pool_id, coin_spent, paid_at_ms)
|
||||
3. ExecuteLuckyGiftDraw(command_id, user_id, target_user_id, gift_count, device_id, room_id, anchor_id, gift_id, pool_id, coin_spent, paid_at_ms)
|
||||
4. activity-service 本地事务写 draw fact + outbox
|
||||
5. 事务后由钱包/房间表现链路处理 reward_status=pending 的结果
|
||||
5. lucky gift worker 幂等调用 wallet-service.CreditLuckyGiftReward
|
||||
6. wallet-service 写 WalletBalanceChanged,notice-service 投递私信余额通知
|
||||
7. lucky gift worker 投递房间群 IM lucky_gift_drawn
|
||||
8. activity-service 标记 reward_status=granted、outbox=delivered
|
||||
```
|
||||
|
||||
`command_id` 是抽奖幂等键。重复 `ExecuteLuckyGiftDraw` 会返回同一条 `lucky_draw_records`,不会重复消耗 RTP、奖池或预算。
|
||||
|
||||
@ -17,6 +17,13 @@ first_recharge_reward_worker:
|
||||
enabled: false
|
||||
red_packet_broadcast_worker:
|
||||
enabled: false
|
||||
lucky_gift_worker:
|
||||
enabled: true
|
||||
worker_poll_interval: "1s"
|
||||
worker_batch_size: 100
|
||||
worker_lock_ttl: "30s"
|
||||
worker_max_retry: 8
|
||||
publish_timeout: "5s"
|
||||
tencent_im:
|
||||
# Docker 本地联调全局/区域播报群;必须与 gateway/room-service 使用同一组腾讯 IM 应用配置。
|
||||
enabled: true
|
||||
|
||||
@ -17,6 +17,13 @@ first_recharge_reward_worker:
|
||||
enabled: true
|
||||
red_packet_broadcast_worker:
|
||||
enabled: true
|
||||
lucky_gift_worker:
|
||||
enabled: true
|
||||
worker_poll_interval: "1s"
|
||||
worker_batch_size: 100
|
||||
worker_lock_ttl: "30s"
|
||||
worker_max_retry: 8
|
||||
publish_timeout: "5s"
|
||||
tencent_im:
|
||||
# 腾讯云 IM 应用配置;必须和 gateway 的 UserSig、room-service 房间群配置属于同一个 SDKAppID。
|
||||
enabled: true
|
||||
|
||||
@ -17,6 +17,13 @@ first_recharge_reward_worker:
|
||||
enabled: false
|
||||
red_packet_broadcast_worker:
|
||||
enabled: false
|
||||
lucky_gift_worker:
|
||||
enabled: true
|
||||
worker_poll_interval: "1s"
|
||||
worker_batch_size: 100
|
||||
worker_lock_ttl: "30s"
|
||||
worker_max_retry: 8
|
||||
publish_timeout: "5s"
|
||||
tencent_im:
|
||||
# activity-service 只负责全局/区域播报群;必须与 gateway/room-service 使用同一组腾讯 IM 应用配置。
|
||||
enabled: true
|
||||
|
||||
@ -38,6 +38,9 @@ CREATE TABLE IF NOT EXISTS activity_outbox (
|
||||
status VARCHAR(32) NOT NULL COMMENT '业务状态',
|
||||
retry_count INT NOT NULL DEFAULT 0 COMMENT '重试次数',
|
||||
next_retry_at_ms BIGINT NOT NULL COMMENT '下一次重试时间,UTC epoch ms',
|
||||
locked_by VARCHAR(128) NOT NULL DEFAULT '' COMMENT '当前锁定 worker',
|
||||
lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT '锁过期时间,UTC epoch ms',
|
||||
last_error VARCHAR(512) NOT NULL DEFAULT '' COMMENT '最后一次失败原因',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
PRIMARY KEY (app_code, outbox_id),
|
||||
@ -194,6 +197,8 @@ CREATE TABLE IF NOT EXISTS lucky_draw_records (
|
||||
pool_snapshot_json JSON NOT NULL COMMENT '奖池快照',
|
||||
rtp_snapshot_json JSON NOT NULL COMMENT 'RTP 快照',
|
||||
reward_status VARCHAR(32) NOT NULL COMMENT 'pending/granted/failed',
|
||||
reward_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '返奖钱包交易 ID',
|
||||
reward_failure_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '返奖失败原因',
|
||||
paid_at_ms BIGINT NOT NULL COMMENT '扣费时间,UTC epoch ms',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
|
||||
@ -49,9 +49,12 @@ type App struct {
|
||||
healthHTTP *healthhttp.Server
|
||||
mysqlRepo *mysqlstorage.Repository
|
||||
broadcast *broadcastservice.Service
|
||||
luckyGift *luckygiftservice.Service
|
||||
firstRechargeReward *firstrechargeservice.Service
|
||||
broadcastWorkerEnabled bool
|
||||
luckyGiftWorkerEnabled bool
|
||||
workerNodeID string
|
||||
luckyGiftWorkerOptions luckygiftservice.WorkerOptions
|
||||
mqConsumers []*rocketmqx.Consumer
|
||||
userConn *grpc.ClientConn
|
||||
walletConn *grpc.ClientConn
|
||||
@ -105,10 +108,10 @@ func New(cfg config.Config) (*App, error) {
|
||||
sevenDayCheckInSvc := sevendaycheckinservice.New(repository, walletv1.NewWalletServiceClient(walletConn))
|
||||
growthSvc := growthservice.New(repository, walletv1.NewWalletServiceClient(walletConn))
|
||||
achievementSvc := achievementservice.New(repository, walletv1.NewWalletServiceClient(walletConn))
|
||||
luckyGiftSvc := luckygiftservice.New(repository)
|
||||
var tencentClient *tencentim.RESTClient
|
||||
var broadcastPublisher broadcastservice.Publisher
|
||||
if cfg.TencentIM.Enabled {
|
||||
tencentClient, err := tencentim.NewRESTClient(cfg.TencentIM.RESTConfig())
|
||||
tencentClient, err = tencentim.NewRESTClient(cfg.TencentIM.RESTConfig())
|
||||
if err != nil {
|
||||
_ = walletConn.Close()
|
||||
_ = userConn.Close()
|
||||
@ -118,6 +121,10 @@ func New(cfg config.Config) (*App, error) {
|
||||
}
|
||||
broadcastPublisher = tencentClient
|
||||
}
|
||||
luckyGiftSvc := luckygiftservice.New(repository,
|
||||
luckygiftservice.WithWallet(walletv1.NewWalletServiceClient(walletConn)),
|
||||
luckygiftservice.WithRoomPublisher(tencentClient),
|
||||
)
|
||||
if cfg.Broadcast.Enabled && broadcastPublisher == nil {
|
||||
_ = walletConn.Close()
|
||||
_ = userConn.Close()
|
||||
@ -263,9 +270,12 @@ func New(cfg config.Config) (*App, error) {
|
||||
healthHTTP: healthHTTP,
|
||||
mysqlRepo: repository,
|
||||
broadcast: broadcastSvc,
|
||||
luckyGift: luckyGiftSvc,
|
||||
firstRechargeReward: firstRechargeRewardSvc,
|
||||
broadcastWorkerEnabled: cfg.Broadcast.Enabled,
|
||||
luckyGiftWorkerEnabled: cfg.LuckyGiftWorker.Enabled,
|
||||
workerNodeID: cfg.NodeID,
|
||||
luckyGiftWorkerOptions: luckyGiftWorkerOptions(cfg.NodeID, cfg.LuckyGiftWorker),
|
||||
mqConsumers: mqConsumers,
|
||||
userConn: userConn,
|
||||
walletConn: walletConn,
|
||||
@ -287,6 +297,11 @@ func (a *App) Run() error {
|
||||
a.broadcast.RunWorker(a.workerCtx, broadcastservice.WorkerOptions{})
|
||||
})
|
||||
}
|
||||
if a.luckyGiftWorkerEnabled && a.luckyGift != nil && a.workerCtx != nil {
|
||||
a.workerWG.Go(func() {
|
||||
a.luckyGift.RunWorker(a.workerCtx, a.luckyGiftWorkerOptions)
|
||||
})
|
||||
}
|
||||
err := a.server.Serve(a.listener)
|
||||
if a.workerStop != nil {
|
||||
a.workerStop()
|
||||
@ -481,3 +496,14 @@ func redPacketRegionIDFromWalletPayload(payload string) int64 {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func luckyGiftWorkerOptions(nodeID string, cfg config.LuckyGiftWorkerConfig) luckygiftservice.WorkerOptions {
|
||||
return luckygiftservice.WorkerOptions{
|
||||
WorkerID: nodeID + "-lucky-gift",
|
||||
PollInterval: cfg.WorkerPollInterval,
|
||||
BatchSize: cfg.WorkerBatchSize,
|
||||
LockTTL: cfg.WorkerLockTTL,
|
||||
MaxRetry: cfg.WorkerMaxRetry,
|
||||
PublishTimeout: cfg.PublishTimeout,
|
||||
}
|
||||
}
|
||||
|
||||
@ -29,6 +29,8 @@ type Config struct {
|
||||
FirstRechargeRewardWorker FirstRechargeRewardWorkerConfig `yaml:"first_recharge_reward_worker"`
|
||||
// RedPacketBroadcastWorker 控制红包创建事实转区域飘屏 outbox 的本地消费。
|
||||
RedPacketBroadcastWorker RedPacketBroadcastWorkerConfig `yaml:"red_packet_broadcast_worker"`
|
||||
// LuckyGiftWorker 控制幸运礼物 draw outbox 的返奖和房间 IM 补偿。
|
||||
LuckyGiftWorker LuckyGiftWorkerConfig `yaml:"lucky_gift_worker"`
|
||||
// TencentIM 是 activity-service 发送全局/区域播报群消息的 REST 配置。
|
||||
TencentIM TencentIMConfig `yaml:"tencent_im"`
|
||||
// Broadcast 控制 IM 播报群 reconciler、outbox worker 和贵重礼物阈值。
|
||||
@ -65,6 +67,16 @@ type RedPacketBroadcastWorkerConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
// LuckyGiftWorkerConfig 保存幸运礼物抽奖副作用补偿策略。
|
||||
type LuckyGiftWorkerConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
WorkerPollInterval time.Duration `yaml:"worker_poll_interval"`
|
||||
WorkerBatchSize int `yaml:"worker_batch_size"`
|
||||
WorkerLockTTL time.Duration `yaml:"worker_lock_ttl"`
|
||||
WorkerMaxRetry int `yaml:"worker_max_retry"`
|
||||
PublishTimeout time.Duration `yaml:"publish_timeout"`
|
||||
}
|
||||
|
||||
// TencentIMConfig 描述 activity-service 调用腾讯云 IM REST API 的配置。
|
||||
type TencentIMConfig struct {
|
||||
Enabled bool `yaml:"enabled"`
|
||||
@ -153,6 +165,14 @@ func Default() Config {
|
||||
RedPacketBroadcastWorker: RedPacketBroadcastWorkerConfig{
|
||||
Enabled: false,
|
||||
},
|
||||
LuckyGiftWorker: LuckyGiftWorkerConfig{
|
||||
Enabled: false,
|
||||
WorkerPollInterval: time.Second,
|
||||
WorkerBatchSize: 100,
|
||||
WorkerLockTTL: 30 * time.Second,
|
||||
WorkerMaxRetry: 8,
|
||||
PublishTimeout: 5 * time.Second,
|
||||
},
|
||||
TencentIM: TencentIMConfig{
|
||||
Enabled: false,
|
||||
AdminIdentifier: "administrator",
|
||||
@ -271,6 +291,21 @@ func Load(path string) (Config, error) {
|
||||
if cfg.Broadcast.WorkerMaxRetry <= 0 {
|
||||
cfg.Broadcast.WorkerMaxRetry = 8
|
||||
}
|
||||
if cfg.LuckyGiftWorker.WorkerPollInterval <= 0 {
|
||||
cfg.LuckyGiftWorker.WorkerPollInterval = time.Second
|
||||
}
|
||||
if cfg.LuckyGiftWorker.WorkerBatchSize <= 0 {
|
||||
cfg.LuckyGiftWorker.WorkerBatchSize = 100
|
||||
}
|
||||
if cfg.LuckyGiftWorker.WorkerLockTTL <= 0 {
|
||||
cfg.LuckyGiftWorker.WorkerLockTTL = 30 * time.Second
|
||||
}
|
||||
if cfg.LuckyGiftWorker.WorkerMaxRetry <= 0 {
|
||||
cfg.LuckyGiftWorker.WorkerMaxRetry = 8
|
||||
}
|
||||
if cfg.LuckyGiftWorker.PublishTimeout <= 0 {
|
||||
cfg.LuckyGiftWorker.PublishTimeout = 5 * time.Second
|
||||
}
|
||||
rocketMQ, err := normalizeRocketMQConfig(cfg.RocketMQ)
|
||||
if err != nil {
|
||||
return Config{}, err
|
||||
@ -279,6 +314,9 @@ func Load(path string) (Config, error) {
|
||||
if (cfg.FirstRechargeRewardWorker.Enabled || cfg.RedPacketBroadcastWorker.Enabled) && !cfg.RocketMQ.WalletOutbox.Enabled {
|
||||
return Config{}, errors.New("wallet outbox workers require rocketmq.wallet_outbox.enabled")
|
||||
}
|
||||
if cfg.LuckyGiftWorker.Enabled && !cfg.TencentIM.Enabled {
|
||||
return Config{}, errors.New("lucky gift worker requires tencent_im.enabled")
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
@ -8,6 +8,8 @@ const (
|
||||
StatusPaused = "paused"
|
||||
StatusClosed = "closed"
|
||||
StatusPending = "pending"
|
||||
StatusGranted = "granted"
|
||||
StatusFailed = "failed"
|
||||
|
||||
PoolNovice = "novice"
|
||||
PoolIntermediate = "intermediate"
|
||||
@ -82,15 +84,17 @@ type CheckCommand struct {
|
||||
}
|
||||
|
||||
type DrawCommand struct {
|
||||
CommandID string
|
||||
PoolID string
|
||||
UserID int64
|
||||
DeviceID string
|
||||
RoomID string
|
||||
AnchorID string
|
||||
GiftID string
|
||||
CoinSpent int64
|
||||
PaidAtMS int64
|
||||
CommandID string
|
||||
PoolID string
|
||||
UserID int64
|
||||
TargetUserID int64
|
||||
DeviceID string
|
||||
RoomID string
|
||||
AnchorID string
|
||||
GiftID string
|
||||
GiftCount int32
|
||||
CoinSpent int64
|
||||
PaidAtMS int64
|
||||
}
|
||||
|
||||
type CheckResult struct {
|
||||
@ -157,3 +161,13 @@ type DrawQuery struct {
|
||||
Page int32
|
||||
PageSize int32
|
||||
}
|
||||
|
||||
// DrawOutbox 是幸运礼物抽奖事务写出的异步副作用载体,worker 只消费这个持久事实。
|
||||
type DrawOutbox struct {
|
||||
AppCode string
|
||||
OutboxID string
|
||||
EventType string
|
||||
PayloadJSON string
|
||||
RetryCount int
|
||||
CreatedAtMS int64
|
||||
}
|
||||
|
||||
@ -2,10 +2,17 @@ package luckygift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
walletv1 "hyapp.local/api/proto/wallet/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/logx"
|
||||
"hyapp/pkg/tencentim"
|
||||
"hyapp/pkg/xerr"
|
||||
domain "hyapp/services/activity-service/internal/domain/luckygift"
|
||||
)
|
||||
@ -19,16 +26,54 @@ type Repository interface {
|
||||
ExecuteLuckyGiftDraw(ctx context.Context, cmd domain.DrawCommand, nowMS int64) (domain.DrawResult, error)
|
||||
ListLuckyGiftDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error)
|
||||
GetLuckyGiftDrawSummary(ctx context.Context, query domain.DrawQuery) (domain.DrawSummary, error)
|
||||
ClaimPendingLuckyGiftOutbox(ctx context.Context, workerID string, nowMS int64, lockTTL time.Duration, batchSize int) ([]domain.DrawOutbox, error)
|
||||
MarkLuckyGiftOutboxDelivered(ctx context.Context, event domain.DrawOutbox, nowMS int64) error
|
||||
MarkLuckyGiftOutboxRetryable(ctx context.Context, event domain.DrawOutbox, retryCount int, nextRetryAtMS int64, lastErr string, nowMS int64) error
|
||||
MarkLuckyGiftOutboxFailed(ctx context.Context, event domain.DrawOutbox, retryCount int, lastErr string, nowMS int64) error
|
||||
MarkLuckyGiftDrawGranted(ctx context.Context, appCode string, drawID string, walletTransactionID string, nowMS int64) error
|
||||
MarkLuckyGiftDrawFailed(ctx context.Context, appCode string, drawID string, failureReason string, nowMS int64) error
|
||||
}
|
||||
|
||||
// WalletClient 是幸运礼物返奖唯一账务依赖;实际余额变更通知继续由 wallet outbox -> notice-service 投递。
|
||||
type WalletClient interface {
|
||||
CreditLuckyGiftReward(ctx context.Context, req *walletv1.CreditLuckyGiftRewardRequest, opts ...grpc.CallOption) (*walletv1.CreditLuckyGiftRewardResponse, error)
|
||||
}
|
||||
|
||||
// RoomPublisher 只负责投递房间群自定义消息,不拥有房间状态。
|
||||
type RoomPublisher interface {
|
||||
PublishGroupCustomMessage(ctx context.Context, message tencentim.CustomGroupMessage) error
|
||||
}
|
||||
|
||||
// Service 承载幸运礼物查询、抽奖命令和后台规则配置。
|
||||
type Service struct {
|
||||
repository Repository
|
||||
wallet WalletClient
|
||||
publisher RoomPublisher
|
||||
now func() time.Time
|
||||
}
|
||||
|
||||
func New(repository Repository) *Service {
|
||||
return &Service{repository: repository, now: time.Now}
|
||||
type Option func(*Service)
|
||||
|
||||
func WithWallet(client WalletClient) Option {
|
||||
return func(s *Service) {
|
||||
s.wallet = client
|
||||
}
|
||||
}
|
||||
|
||||
func WithRoomPublisher(publisher RoomPublisher) Option {
|
||||
return func(s *Service) {
|
||||
s.publisher = publisher
|
||||
}
|
||||
}
|
||||
|
||||
func New(repository Repository, options ...Option) *Service {
|
||||
service := &Service{repository: repository, now: time.Now}
|
||||
for _, option := range options {
|
||||
if option != nil {
|
||||
option(service)
|
||||
}
|
||||
}
|
||||
return service
|
||||
}
|
||||
|
||||
func (s *Service) SetClock(now func() time.Time) {
|
||||
@ -63,12 +108,131 @@ func (s *Service) Draw(ctx context.Context, cmd domain.DrawCommand) (domain.Draw
|
||||
if cmd.CommandID == "" || cmd.UserID <= 0 || cmd.DeviceID == "" || cmd.RoomID == "" || cmd.AnchorID == "" || cmd.GiftID == "" || cmd.CoinSpent <= 0 {
|
||||
return domain.DrawResult{}, xerr.New(xerr.InvalidArgument, "lucky gift draw command is incomplete")
|
||||
}
|
||||
if cmd.TargetUserID < 0 || cmd.GiftCount < 0 {
|
||||
return domain.DrawResult{}, xerr.New(xerr.InvalidArgument, "lucky gift draw metadata is invalid")
|
||||
}
|
||||
if cmd.PaidAtMS <= 0 {
|
||||
cmd.PaidAtMS = s.now().UTC().UnixMilli()
|
||||
}
|
||||
return s.repository.ExecuteLuckyGiftDraw(ctx, cmd, s.now().UTC().UnixMilli())
|
||||
}
|
||||
|
||||
type WorkerOptions struct {
|
||||
WorkerID string
|
||||
PollInterval time.Duration
|
||||
BatchSize int
|
||||
LockTTL time.Duration
|
||||
MaxRetry int
|
||||
PublishTimeout time.Duration
|
||||
}
|
||||
|
||||
func (s *Service) RunWorker(ctx context.Context, options WorkerOptions) {
|
||||
options = normalizeWorkerOptions(options)
|
||||
ticker := time.NewTicker(options.PollInterval)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
if _, err := s.ProcessPendingDrawOutbox(ctx, options); err != nil && ctx.Err() == nil {
|
||||
// 批处理失败不删除 outbox;锁过期后下一轮或其他实例会继续补偿。
|
||||
logx.Error(ctx, "lucky_gift_outbox_batch_failed", err, slog.String("worker_id", options.WorkerID))
|
||||
}
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) ProcessPendingDrawOutbox(ctx context.Context, options WorkerOptions) (int, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
options = normalizeWorkerOptions(options)
|
||||
events, err := s.repository.ClaimPendingLuckyGiftOutbox(ctx, options.WorkerID, s.now().UTC().UnixMilli(), options.LockTTL, options.BatchSize)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
processed := 0
|
||||
for _, event := range events {
|
||||
if err := s.processDrawOutbox(ctx, event, options); err != nil {
|
||||
return processed, err
|
||||
}
|
||||
processed++
|
||||
}
|
||||
return processed, nil
|
||||
}
|
||||
|
||||
func (s *Service) processDrawOutbox(ctx context.Context, event domain.DrawOutbox, options WorkerOptions) error {
|
||||
payload, err := decodeDrawOutboxPayload(event.PayloadJSON)
|
||||
if err != nil {
|
||||
return s.markOutboxFailed(ctx, event, options, err, false)
|
||||
}
|
||||
eventCtx := appcode.WithContext(ctx, event.AppCode)
|
||||
walletTransactionID := ""
|
||||
credited := false
|
||||
if payload.EffectiveRewardCoins > 0 {
|
||||
if s.wallet == nil {
|
||||
return s.markOutboxFailed(eventCtx, event, options, fmt.Errorf("lucky gift wallet client is not configured"), false)
|
||||
}
|
||||
resp, err := s.wallet.CreditLuckyGiftReward(eventCtx, &walletv1.CreditLuckyGiftRewardRequest{
|
||||
CommandId: "lucky_reward:" + payload.DrawID,
|
||||
AppCode: event.AppCode,
|
||||
TargetUserId: payload.UserID,
|
||||
Amount: payload.EffectiveRewardCoins,
|
||||
DrawId: payload.DrawID,
|
||||
RoomId: payload.RoomID,
|
||||
GiftId: payload.GiftID,
|
||||
PoolId: payload.PoolID,
|
||||
Reason: "lucky_gift_reward",
|
||||
})
|
||||
if err != nil {
|
||||
return s.markOutboxFailed(eventCtx, event, options, err, false)
|
||||
}
|
||||
walletTransactionID = resp.GetTransactionId()
|
||||
credited = true
|
||||
}
|
||||
if s.publisher == nil {
|
||||
return s.markOutboxFailed(eventCtx, event, options, fmt.Errorf("lucky gift room publisher is not configured"), credited)
|
||||
}
|
||||
if err := s.publishLuckyGiftDrawn(eventCtx, payload, options); err != nil {
|
||||
return s.markOutboxFailed(eventCtx, event, options, err, credited)
|
||||
}
|
||||
nowMS := s.now().UTC().UnixMilli()
|
||||
if err := s.repository.MarkLuckyGiftDrawGranted(eventCtx, event.AppCode, payload.DrawID, walletTransactionID, nowMS); err != nil {
|
||||
return err
|
||||
}
|
||||
return s.repository.MarkLuckyGiftOutboxDelivered(eventCtx, event, nowMS)
|
||||
}
|
||||
|
||||
func (s *Service) publishLuckyGiftDrawn(ctx context.Context, payload luckyGiftDrawnPayload, options WorkerOptions) error {
|
||||
body, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
publishCtx, cancel := context.WithTimeout(ctx, options.PublishTimeout)
|
||||
defer cancel()
|
||||
return s.publisher.PublishGroupCustomMessage(publishCtx, tencentim.CustomGroupMessage{
|
||||
GroupID: payload.RoomID,
|
||||
EventID: payload.EventID,
|
||||
Desc: "lucky_gift_drawn",
|
||||
Ext: "room_system_message",
|
||||
PayloadJSON: body,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Service) markOutboxFailed(ctx context.Context, event domain.DrawOutbox, options WorkerOptions, cause error, alreadyCredited bool) error {
|
||||
nowMS := s.now().UTC().UnixMilli()
|
||||
nextRetryCount := event.RetryCount + 1
|
||||
if nextRetryCount >= options.MaxRetry {
|
||||
if !alreadyCredited {
|
||||
_ = s.repository.MarkLuckyGiftDrawFailed(ctx, event.AppCode, drawIDFromPayload(event.PayloadJSON), cause.Error(), nowMS)
|
||||
}
|
||||
return s.repository.MarkLuckyGiftOutboxFailed(ctx, event, nextRetryCount, cause.Error(), nowMS)
|
||||
}
|
||||
nextRetryAtMS := nowMS + luckyGiftBackoff(nextRetryCount).Milliseconds()
|
||||
return s.repository.MarkLuckyGiftOutboxRetryable(ctx, event, nextRetryCount, nextRetryAtMS, cause.Error(), nowMS)
|
||||
}
|
||||
|
||||
func (s *Service) GetConfig(ctx context.Context, poolID string) (domain.Config, error) {
|
||||
if err := s.requireRepository(); err != nil {
|
||||
return domain.Config{}, err
|
||||
@ -143,3 +307,94 @@ func normalizeDrawQuery(query domain.DrawQuery) domain.DrawQuery {
|
||||
query.Status = strings.TrimSpace(query.Status)
|
||||
return query
|
||||
}
|
||||
|
||||
type luckyGiftDrawnPayload struct {
|
||||
EventType string `json:"event_type"`
|
||||
EventID string `json:"event_id"`
|
||||
AppCode string `json:"app_code"`
|
||||
DrawID string `json:"draw_id"`
|
||||
CommandID string `json:"command_id"`
|
||||
PoolID string `json:"pool_id"`
|
||||
RoomID string `json:"room_id"`
|
||||
GiftID string `json:"gift_id"`
|
||||
GiftCount int32 `json:"gift_count"`
|
||||
UserID int64 `json:"user_id"`
|
||||
SenderUserID int64 `json:"sender_user_id"`
|
||||
TargetUserID int64 `json:"target_user_id"`
|
||||
CoinSpent int64 `json:"coin_spent"`
|
||||
RuleVersion int64 `json:"rule_version"`
|
||||
ExperiencePool string `json:"experience_pool"`
|
||||
SelectedTierID string `json:"selected_tier_id"`
|
||||
MultiplierPPM int64 `json:"multiplier_ppm"`
|
||||
BaseRewardCoins int64 `json:"base_reward_coins"`
|
||||
RoomAtmosphereRewardCoins int64 `json:"room_atmosphere_reward_coins"`
|
||||
ActivitySubsidyCoins int64 `json:"activity_subsidy_coins"`
|
||||
EffectiveRewardCoins int64 `json:"effective_reward_coins"`
|
||||
StageFeedback bool `json:"stage_feedback"`
|
||||
HighMultiplier bool `json:"high_multiplier"`
|
||||
CreatedAtMS int64 `json:"created_at_ms"`
|
||||
}
|
||||
|
||||
func decodeDrawOutboxPayload(payloadJSON string) (luckyGiftDrawnPayload, error) {
|
||||
var payload luckyGiftDrawnPayload
|
||||
if err := json.Unmarshal([]byte(payloadJSON), &payload); err != nil {
|
||||
return luckyGiftDrawnPayload{}, fmt.Errorf("invalid lucky gift outbox payload: %w", err)
|
||||
}
|
||||
if payload.EventType == "" {
|
||||
payload.EventType = "lucky_gift_drawn"
|
||||
}
|
||||
if payload.EventID == "" && payload.DrawID != "" {
|
||||
payload.EventID = "lucky_gift_drawn:" + payload.DrawID
|
||||
}
|
||||
if payload.SenderUserID == 0 {
|
||||
payload.SenderUserID = payload.UserID
|
||||
}
|
||||
if payload.DrawID == "" || payload.EventID == "" || payload.RoomID == "" || payload.GiftID == "" || payload.UserID <= 0 {
|
||||
return luckyGiftDrawnPayload{}, fmt.Errorf("lucky gift outbox payload is incomplete")
|
||||
}
|
||||
return payload, nil
|
||||
}
|
||||
|
||||
func drawIDFromPayload(payloadJSON string) string {
|
||||
payload, err := decodeDrawOutboxPayload(payloadJSON)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return payload.DrawID
|
||||
}
|
||||
|
||||
func normalizeWorkerOptions(options WorkerOptions) WorkerOptions {
|
||||
options.WorkerID = strings.TrimSpace(options.WorkerID)
|
||||
if options.WorkerID == "" {
|
||||
options.WorkerID = "lucky-gift-worker"
|
||||
}
|
||||
if options.PollInterval <= 0 {
|
||||
options.PollInterval = time.Second
|
||||
}
|
||||
if options.BatchSize <= 0 {
|
||||
options.BatchSize = 100
|
||||
}
|
||||
if options.BatchSize > 500 {
|
||||
options.BatchSize = 500
|
||||
}
|
||||
if options.LockTTL <= 0 {
|
||||
options.LockTTL = 30 * time.Second
|
||||
}
|
||||
if options.MaxRetry <= 0 {
|
||||
options.MaxRetry = 8
|
||||
}
|
||||
if options.PublishTimeout <= 0 {
|
||||
options.PublishTimeout = 5 * time.Second
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
func luckyGiftBackoff(retryCount int) time.Duration {
|
||||
if retryCount < 1 {
|
||||
retryCount = 1
|
||||
}
|
||||
if retryCount > 6 {
|
||||
retryCount = 6
|
||||
}
|
||||
return time.Duration(1<<retryCount) * time.Second
|
||||
}
|
||||
|
||||
@ -2,9 +2,14 @@ package luckygift
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
walletv1 "hyapp.local/api/proto/wallet/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/tencentim"
|
||||
domain "hyapp/services/activity-service/internal/domain/luckygift"
|
||||
)
|
||||
|
||||
@ -38,9 +43,64 @@ func TestUpsertConfigPreservesPoolScope(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessPendingDrawOutboxCreditsWalletAndPublishesRoomIM(t *testing.T) {
|
||||
payload, _ := json.Marshal(map[string]any{
|
||||
"event_type": "lucky_gift_drawn",
|
||||
"event_id": "lucky_gift_drawn:lucky_draw_test",
|
||||
"app_code": "lalu",
|
||||
"draw_id": "lucky_draw_test",
|
||||
"command_id": "cmd-gift",
|
||||
"pool_id": "super_lucky",
|
||||
"user_id": 42,
|
||||
"sender_user_id": 42,
|
||||
"target_user_id": 99,
|
||||
"room_id": "room-1",
|
||||
"gift_id": "rose",
|
||||
"gift_count": 1,
|
||||
"coin_spent": 100,
|
||||
"effective_reward_coins": 300,
|
||||
"multiplier_ppm": 3000000,
|
||||
"stage_feedback": true,
|
||||
"created_at_ms": 1760000000000,
|
||||
})
|
||||
repository := &fakeLuckyGiftRepository{
|
||||
outbox: []domain.DrawOutbox{{
|
||||
AppCode: "lalu",
|
||||
OutboxID: "lucky_lucky_draw_test",
|
||||
EventType: "LuckyGiftDrawn",
|
||||
PayloadJSON: string(payload),
|
||||
}},
|
||||
}
|
||||
wallet := &fakeLuckyGiftWallet{}
|
||||
publisher := &fakeLuckyGiftPublisher{}
|
||||
service := New(repository, WithWallet(wallet), WithRoomPublisher(publisher))
|
||||
service.SetClock(func() time.Time { return time.UnixMilli(1760000001000).UTC() })
|
||||
|
||||
processed, err := service.ProcessPendingDrawOutbox(context.Background(), WorkerOptions{WorkerID: "worker-1"})
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessPendingDrawOutbox failed: %v", err)
|
||||
}
|
||||
if processed != 1 {
|
||||
t.Fatalf("processed count mismatch: %d", processed)
|
||||
}
|
||||
if wallet.last == nil || wallet.last.GetDrawId() != "lucky_draw_test" || wallet.last.GetTargetUserId() != 42 || wallet.last.GetAmount() != 300 {
|
||||
t.Fatalf("wallet reward request mismatch: %+v", wallet.last)
|
||||
}
|
||||
if publisher.last.GroupID != "room-1" || publisher.last.Desc != "lucky_gift_drawn" || publisher.last.EventID != "lucky_gift_drawn:lucky_draw_test" {
|
||||
t.Fatalf("room im message mismatch: %+v", publisher.last)
|
||||
}
|
||||
if repository.grantedDrawID != "lucky_draw_test" || repository.deliveredOutboxID != "lucky_lucky_draw_test" {
|
||||
t.Fatalf("repository settlement mismatch: granted=%s delivered=%s", repository.grantedDrawID, repository.deliveredOutboxID)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeLuckyGiftRepository struct {
|
||||
getConfigCalls int
|
||||
upserted domain.Config
|
||||
outbox []domain.DrawOutbox
|
||||
|
||||
grantedDrawID string
|
||||
deliveredOutboxID string
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) GetLuckyGiftConfig(context.Context, string) (domain.Config, bool, error) {
|
||||
@ -72,3 +132,47 @@ func (r *fakeLuckyGiftRepository) ListLuckyGiftDraws(context.Context, domain.Dra
|
||||
func (r *fakeLuckyGiftRepository) GetLuckyGiftDrawSummary(context.Context, domain.DrawQuery) (domain.DrawSummary, error) {
|
||||
return domain.DrawSummary{}, nil
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) ClaimPendingLuckyGiftOutbox(context.Context, string, int64, time.Duration, int) ([]domain.DrawOutbox, error) {
|
||||
return r.outbox, nil
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) MarkLuckyGiftOutboxDelivered(_ context.Context, event domain.DrawOutbox, _ int64) error {
|
||||
r.deliveredOutboxID = event.OutboxID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) MarkLuckyGiftOutboxRetryable(context.Context, domain.DrawOutbox, int, int64, string, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) MarkLuckyGiftOutboxFailed(context.Context, domain.DrawOutbox, int, string, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) MarkLuckyGiftDrawGranted(_ context.Context, _ string, drawID string, _ string, _ int64) error {
|
||||
r.grantedDrawID = drawID
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *fakeLuckyGiftRepository) MarkLuckyGiftDrawFailed(context.Context, string, string, string, int64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type fakeLuckyGiftWallet struct {
|
||||
last *walletv1.CreditLuckyGiftRewardRequest
|
||||
}
|
||||
|
||||
func (w *fakeLuckyGiftWallet) CreditLuckyGiftReward(_ context.Context, req *walletv1.CreditLuckyGiftRewardRequest, _ ...grpc.CallOption) (*walletv1.CreditLuckyGiftRewardResponse, error) {
|
||||
w.last = req
|
||||
return &walletv1.CreditLuckyGiftRewardResponse{TransactionId: "wallet_tx_lucky", Amount: req.GetAmount()}, nil
|
||||
}
|
||||
|
||||
type fakeLuckyGiftPublisher struct {
|
||||
last tencentim.CustomGroupMessage
|
||||
}
|
||||
|
||||
func (p *fakeLuckyGiftPublisher) PublishGroupCustomMessage(_ context.Context, message tencentim.CustomGroupMessage) error {
|
||||
p.last = message
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -556,33 +556,51 @@ func (r *Repository) applyLuckyDraw(ctx context.Context, tx *sql.Tx, input lucky
|
||||
coin_spent, rule_version, experience_pool, rtp_window_index, gift_rtp_window_index,
|
||||
selected_tier_id, base_reward_coins, room_atmosphere_reward_coins, activity_subsidy_coins,
|
||||
effective_reward_coins, budget_sources_json, stage_feedback, high_multiplier,
|
||||
candidate_tiers_json, pool_snapshot_json, rtp_snapshot_json, reward_status,
|
||||
candidate_tiers_json, pool_snapshot_json, rtp_snapshot_json, reward_status, reward_transaction_id, reward_failure_reason,
|
||||
paid_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)`,
|
||||
input.AppCode, input.DrawID, input.Command.CommandID, input.Command.UserID, input.Command.DeviceID,
|
||||
input.Command.RoomID, input.Command.AnchorID, input.Config.GiftID, input.Command.GiftID, input.Command.CoinSpent,
|
||||
input.Config.RuleVersion, input.ExperiencePool, input.GlobalWindow.WindowIndex, input.GiftWindow.WindowIndex,
|
||||
input.Candidate.TierID, input.Candidate.BaseReward, input.Candidate.RoomReward, input.Candidate.ActivityReward,
|
||||
input.Candidate.effectiveReward(), input.BudgetSourcesJSON, input.StageFeedback, input.Candidate.HighMultiplier,
|
||||
string(candidateSnapshot), string(poolSnapshot), string(rtpSnapshot), domain.StatusPending,
|
||||
string(candidateSnapshot), string(poolSnapshot), string(rtpSnapshot), domain.StatusPending, "", "",
|
||||
input.Command.PaidAtMS, input.NowMS, input.NowMS,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
if input.Candidate.effectiveReward() > 0 || input.StageFeedback || input.Candidate.Presentation {
|
||||
payload, _ := json.Marshal(map[string]any{
|
||||
"draw_id": input.DrawID,
|
||||
"pool_id": input.Config.GiftID,
|
||||
"user_id": input.Command.UserID,
|
||||
"room_id": input.Command.RoomID,
|
||||
"gift_id": input.Command.GiftID,
|
||||
"effective_reward_coins": input.Candidate.effectiveReward(),
|
||||
"stage_feedback": input.StageFeedback,
|
||||
"event_type": "lucky_gift_drawn",
|
||||
"event_id": "lucky_gift_drawn:" + input.DrawID,
|
||||
"app_code": input.AppCode,
|
||||
"draw_id": input.DrawID,
|
||||
"command_id": input.Command.CommandID,
|
||||
"pool_id": input.Config.GiftID,
|
||||
"user_id": input.Command.UserID,
|
||||
"sender_user_id": input.Command.UserID,
|
||||
"target_user_id": input.Command.TargetUserID,
|
||||
"room_id": input.Command.RoomID,
|
||||
"gift_id": input.Command.GiftID,
|
||||
"gift_count": input.Command.GiftCount,
|
||||
"coin_spent": input.Command.CoinSpent,
|
||||
"rule_version": input.Config.RuleVersion,
|
||||
"experience_pool": input.ExperiencePool,
|
||||
"selected_tier_id": input.Candidate.TierID,
|
||||
"multiplier_ppm": input.Candidate.MultiplierPPM,
|
||||
"base_reward_coins": input.Candidate.BaseReward,
|
||||
"room_atmosphere_reward_coins": input.Candidate.RoomReward,
|
||||
"activity_subsidy_coins": input.Candidate.ActivityReward,
|
||||
"effective_reward_coins": input.Candidate.effectiveReward(),
|
||||
"stage_feedback": input.StageFeedback,
|
||||
"high_multiplier": input.Candidate.HighMultiplier,
|
||||
"created_at_ms": input.NowMS,
|
||||
})
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO activity_outbox (
|
||||
app_code, outbox_id, event_type, payload, status, retry_count, next_retry_at_ms, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, 'LuckyGiftDrawn', ?, 'pending', 0, ?, ?, ?)`,
|
||||
app_code, outbox_id, event_type, payload, status, retry_count, next_retry_at_ms,
|
||||
locked_by, lock_until_ms, last_error, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, 'LuckyGiftDrawn', ?, 'pending', 0, ?, '', 0, '', ?, ?)`,
|
||||
input.AppCode, "lucky_"+input.DrawID, payload, input.NowMS, input.NowMS, input.NowMS,
|
||||
); err != nil {
|
||||
return err
|
||||
@ -591,6 +609,155 @@ func (r *Repository) applyLuckyDraw(ctx context.Context, tx *sql.Tx, input lucky
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClaimPendingLuckyGiftOutbox 抢占幸运礼物抽奖副作用。抽奖事实已在同一事务落库,worker 只补偿钱包和房间 IM。
|
||||
func (r *Repository) ClaimPendingLuckyGiftOutbox(ctx context.Context, workerID string, nowMS int64, lockTTL time.Duration, batchSize int) ([]domain.DrawOutbox, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
workerID = strings.TrimSpace(workerID)
|
||||
if workerID == "" {
|
||||
return nil, xerr.New(xerr.InvalidArgument, "worker_id is required")
|
||||
}
|
||||
if batchSize <= 0 {
|
||||
batchSize = 100
|
||||
}
|
||||
if batchSize > 500 {
|
||||
batchSize = 500
|
||||
}
|
||||
if lockTTL <= 0 {
|
||||
lockTTL = 30 * time.Second
|
||||
}
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
rows, err := tx.QueryContext(ctx, `
|
||||
SELECT app_code, outbox_id, event_type, COALESCE(CAST(payload AS CHAR), '{}'), retry_count, created_at_ms
|
||||
FROM activity_outbox
|
||||
WHERE event_type = 'LuckyGiftDrawn'
|
||||
AND (
|
||||
(status IN ('pending', 'retryable') AND next_retry_at_ms <= ?)
|
||||
OR (status = 'delivering' AND lock_until_ms <= ?)
|
||||
)
|
||||
ORDER BY created_at_ms ASC, outbox_id ASC
|
||||
LIMIT ?
|
||||
FOR UPDATE`, nowMS, nowMS, batchSize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
events := make([]domain.DrawOutbox, 0, batchSize)
|
||||
for rows.Next() {
|
||||
var event domain.DrawOutbox
|
||||
if err := rows.Scan(&event.AppCode, &event.OutboxID, &event.EventType, &event.PayloadJSON, &event.RetryCount, &event.CreatedAtMS); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events = append(events, event)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
lockUntilMS := nowMS + lockTTL.Milliseconds()
|
||||
for _, event := range events {
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE activity_outbox
|
||||
SET status = 'delivering', locked_by = ?, lock_until_ms = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND outbox_id = ?`,
|
||||
workerID, lockUntilMS, nowMS, event.AppCode, event.OutboxID,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
func (r *Repository) MarkLuckyGiftOutboxDelivered(ctx context.Context, event domain.DrawOutbox, nowMS int64) error {
|
||||
if r == nil || r.db == nil {
|
||||
return xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE activity_outbox
|
||||
SET status = 'delivered', locked_by = '', lock_until_ms = 0, last_error = '', updated_at_ms = ?
|
||||
WHERE app_code = ? AND outbox_id = ?`,
|
||||
nowMS, appcode.Normalize(event.AppCode), event.OutboxID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) MarkLuckyGiftOutboxRetryable(ctx context.Context, event domain.DrawOutbox, retryCount int, nextRetryAtMS int64, lastErr string, nowMS int64) error {
|
||||
if r == nil || r.db == nil {
|
||||
return xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE activity_outbox
|
||||
SET status = 'retryable', retry_count = ?, next_retry_at_ms = ?, locked_by = '', lock_until_ms = 0,
|
||||
last_error = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND outbox_id = ?`,
|
||||
retryCount, nextRetryAtMS, trimLuckyLastError(lastErr), nowMS, appcode.Normalize(event.AppCode), event.OutboxID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) MarkLuckyGiftOutboxFailed(ctx context.Context, event domain.DrawOutbox, retryCount int, lastErr string, nowMS int64) error {
|
||||
if r == nil || r.db == nil {
|
||||
return xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE activity_outbox
|
||||
SET status = 'failed', retry_count = ?, locked_by = '', lock_until_ms = 0, last_error = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND outbox_id = ?`,
|
||||
retryCount, trimLuckyLastError(lastErr), nowMS, appcode.Normalize(event.AppCode), event.OutboxID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) MarkLuckyGiftDrawGranted(ctx context.Context, appCode string, drawID string, walletTransactionID string, nowMS int64) error {
|
||||
if r == nil || r.db == nil {
|
||||
return xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE lucky_draw_records
|
||||
SET reward_status = ?, reward_transaction_id = ?, reward_failure_reason = '', updated_at_ms = ?
|
||||
WHERE app_code = ? AND draw_id = ?`,
|
||||
domain.StatusGranted, walletTransactionID, nowMS, appcode.Normalize(appCode), drawID,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) MarkLuckyGiftDrawFailed(ctx context.Context, appCode string, drawID string, failureReason string, nowMS int64) error {
|
||||
if r == nil || r.db == nil || strings.TrimSpace(drawID) == "" {
|
||||
return nil
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE lucky_draw_records
|
||||
SET reward_status = ?, reward_failure_reason = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND draw_id = ? AND reward_status = ?`,
|
||||
domain.StatusFailed, trimLuckyFailureReason(failureReason), nowMS, appcode.Normalize(appCode), drawID, domain.StatusPending,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func trimLuckyLastError(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if len(value) > 512 {
|
||||
return value[:512]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func trimLuckyFailureReason(value string) string {
|
||||
value = strings.TrimSpace(value)
|
||||
if len(value) > 255 {
|
||||
return value[:255]
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func (r *Repository) ListLuckyGiftDraws(ctx context.Context, query domain.DrawQuery) ([]domain.DrawResult, int64, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
|
||||
@ -45,6 +45,15 @@ func (r *Repository) Migrate(ctx context.Context) error {
|
||||
if err := r.ensureLuckyDrawPoolID(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureLuckyGiftOutboxColumns(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureLuckyDrawRewardSettlementColumns(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := r.ensureDefaultLuckyGiftRules(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -94,6 +103,84 @@ func (r *Repository) ensureLuckyDrawPoolID(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) ensureLuckyGiftOutboxColumns(ctx context.Context) error {
|
||||
additions := []struct {
|
||||
name string
|
||||
sql string
|
||||
}{
|
||||
{"locked_by", `ALTER TABLE activity_outbox ADD COLUMN locked_by VARCHAR(128) NOT NULL DEFAULT '' COMMENT '当前锁定 worker' AFTER next_retry_at_ms`},
|
||||
{"lock_until_ms", `ALTER TABLE activity_outbox ADD COLUMN lock_until_ms BIGINT NOT NULL DEFAULT 0 COMMENT '锁过期时间,UTC epoch ms' AFTER locked_by`},
|
||||
{"last_error", `ALTER TABLE activity_outbox ADD COLUMN last_error VARCHAR(512) NOT NULL DEFAULT '' COMMENT '最后一次失败原因' AFTER lock_until_ms`},
|
||||
}
|
||||
for _, addition := range additions {
|
||||
exists, err := r.columnExists(ctx, "activity_outbox", addition.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
if _, err := r.db.ExecContext(ctx, addition.sql); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) ensureLuckyDrawRewardSettlementColumns(ctx context.Context) error {
|
||||
additions := []struct {
|
||||
name string
|
||||
sql string
|
||||
}{
|
||||
{"reward_transaction_id", `ALTER TABLE lucky_draw_records ADD COLUMN reward_transaction_id VARCHAR(128) NOT NULL DEFAULT '' COMMENT '返奖钱包交易 ID' AFTER reward_status`},
|
||||
{"reward_failure_reason", `ALTER TABLE lucky_draw_records ADD COLUMN reward_failure_reason VARCHAR(255) NOT NULL DEFAULT '' COMMENT '返奖失败原因' AFTER reward_transaction_id`},
|
||||
}
|
||||
for _, addition := range additions {
|
||||
exists, err := r.columnExists(ctx, "lucky_draw_records", addition.name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
if _, err := r.db.ExecContext(ctx, addition.sql); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repository) ensureDefaultLuckyGiftRules(ctx context.Context) error {
|
||||
// 本地和 Docker 开发库通常保留 MySQL volume;这里补齐缺省 lucky/super_lucky 契约,但不覆盖后台已发布规则。
|
||||
const seedNowMS int64 = 1779259000000
|
||||
const seedTiersJSON = `[
|
||||
{"pool":"novice","tier_id":"novice_none","reward_coins":0,"multiplier_ppm":0,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"novice","tier_id":"novice_1x","reward_coins":100,"multiplier_ppm":1000000,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"novice","tier_id":"novice_2x","reward_coins":200,"multiplier_ppm":2000000,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"intermediate","tier_id":"intermediate_none","reward_coins":0,"multiplier_ppm":0,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"intermediate","tier_id":"intermediate_1x","reward_coins":100,"multiplier_ppm":1000000,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"intermediate","tier_id":"intermediate_2x","reward_coins":200,"multiplier_ppm":2000000,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"advanced","tier_id":"advanced_none","reward_coins":0,"multiplier_ppm":0,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"advanced","tier_id":"advanced_1x","reward_coins":100,"multiplier_ppm":1000000,"weight":0,"high_water_only":false,"enabled":true},
|
||||
{"pool":"advanced","tier_id":"advanced_2x","reward_coins":200,"multiplier_ppm":2000000,"weight":0,"high_water_only":false,"enabled":true}
|
||||
]`
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
INSERT IGNORE 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
|
||||
('lalu', 'lucky', true, 1, 100, 950000, 950000, 100000, 100000, 2000, 20000, 100, 2, 200000, 300000, 500000, 9500000, 23750000, 5000000, 1000000, 1000000, 100000, 50000, 3420000, 61560000, 102600000, 68400000, 1231200000, 10000, 100000, 10000, 0, 0, true, ?, 0, ?, ?),
|
||||
('lalu', 'super_lucky', true, 1, 100, 950000, 950000, 100000, 100000, 2000, 20000, 100, 2, 200000, 300000, 500000, 9500000, 23750000, 5000000, 1000000, 1000000, 100000, 50000, 3420000, 61560000, 102600000, 68400000, 1231200000, 10000, 100000, 10000, 0, 0, true, ?, 0, ?, ?)`,
|
||||
seedTiersJSON, seedNowMS, seedNowMS, seedTiersJSON, seedNowMS, seedNowMS,
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Repository) columnExists(ctx context.Context, table string, column string) (bool, error) {
|
||||
database, err := r.currentDatabase(ctx)
|
||||
if err != nil {
|
||||
|
||||
@ -48,15 +48,17 @@ func (s *LuckyGiftServer) ExecuteLuckyGiftDraw(ctx context.Context, req *activit
|
||||
meta := req.GetLuckyGift()
|
||||
ctx = appcode.WithContext(ctx, meta.GetMeta().GetAppCode())
|
||||
result, err := s.svc.Draw(ctx, domain.DrawCommand{
|
||||
CommandID: meta.GetCommandId(),
|
||||
PoolID: meta.GetPoolId(),
|
||||
UserID: meta.GetUserId(),
|
||||
DeviceID: meta.GetDeviceId(),
|
||||
RoomID: meta.GetRoomId(),
|
||||
AnchorID: meta.GetAnchorId(),
|
||||
GiftID: meta.GetGiftId(),
|
||||
CoinSpent: meta.GetCoinSpent(),
|
||||
PaidAtMS: meta.GetPaidAtMs(),
|
||||
CommandID: meta.GetCommandId(),
|
||||
PoolID: meta.GetPoolId(),
|
||||
UserID: meta.GetUserId(),
|
||||
TargetUserID: meta.GetTargetUserId(),
|
||||
DeviceID: meta.GetDeviceId(),
|
||||
RoomID: meta.GetRoomId(),
|
||||
AnchorID: meta.GetAnchorId(),
|
||||
GiftID: meta.GetGiftId(),
|
||||
GiftCount: meta.GetGiftCount(),
|
||||
CoinSpent: meta.GetCoinSpent(),
|
||||
PaidAtMS: meta.GetPaidAtMs(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
|
||||
@ -99,6 +99,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
var registrationRewardClient client.RegistrationRewardClient = client.NewGRPCRegistrationRewardClient(activityConn)
|
||||
var firstRechargeRewardClient client.FirstRechargeRewardClient = client.NewGRPCFirstRechargeRewardClient(activityConn)
|
||||
var sevenDayCheckInClient client.SevenDayCheckInClient = client.NewGRPCSevenDayCheckInClient(activityConn)
|
||||
var luckyGiftClient client.LuckyGiftClient = client.NewGRPCLuckyGiftClient(activityConn)
|
||||
var broadcastClient client.BroadcastClient = client.NewGRPCBroadcastClient(activityConn)
|
||||
var gameClient client.GameClient = client.NewGRPCGameClient(gameConn)
|
||||
appConfigReader, err := openAppConfigReader(cfg.AppConfig)
|
||||
@ -143,6 +144,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
handler.SetRegistrationRewardClient(registrationRewardClient)
|
||||
handler.SetFirstRechargeRewardClient(firstRechargeRewardClient)
|
||||
handler.SetSevenDayCheckInClient(sevenDayCheckInClient)
|
||||
handler.SetLuckyGiftClient(luckyGiftClient)
|
||||
handler.SetBroadcastClient(broadcastClient)
|
||||
handler.SetGameClient(gameClient)
|
||||
handler.SetLeaderboardWalletDB(leaderboardWalletDB)
|
||||
|
||||
@ -0,0 +1,25 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
)
|
||||
|
||||
// LuckyGiftClient abstracts gateway access to activity-service lucky gift eligibility checks.
|
||||
type LuckyGiftClient interface {
|
||||
CheckLuckyGift(ctx context.Context, req *activityv1.CheckLuckyGiftRequest) (*activityv1.CheckLuckyGiftResponse, error)
|
||||
}
|
||||
|
||||
type grpcLuckyGiftClient struct {
|
||||
client activityv1.LuckyGiftServiceClient
|
||||
}
|
||||
|
||||
func NewGRPCLuckyGiftClient(conn *grpc.ClientConn) LuckyGiftClient {
|
||||
return &grpcLuckyGiftClient{client: activityv1.NewLuckyGiftServiceClient(conn)}
|
||||
}
|
||||
|
||||
func (c *grpcLuckyGiftClient) CheckLuckyGift(ctx context.Context, req *activityv1.CheckLuckyGiftRequest) (*activityv1.CheckLuckyGiftResponse, error) {
|
||||
return c.client.CheckLuckyGift(ctx, req)
|
||||
}
|
||||
@ -20,6 +20,7 @@ type Handler struct {
|
||||
registrationReward client.RegistrationRewardClient
|
||||
firstRechargeReward client.FirstRechargeRewardClient
|
||||
sevenDayCheckIn client.SevenDayCheckInClient
|
||||
luckyGift client.LuckyGiftClient
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@ -33,6 +34,7 @@ type Config struct {
|
||||
RegistrationReward client.RegistrationRewardClient
|
||||
FirstRechargeReward client.FirstRechargeRewardClient
|
||||
SevenDayCheckIn client.SevenDayCheckInClient
|
||||
LuckyGift client.LuckyGiftClient
|
||||
}
|
||||
|
||||
func New(config Config) *Handler {
|
||||
@ -47,6 +49,7 @@ func New(config Config) *Handler {
|
||||
registrationReward: config.RegistrationReward,
|
||||
firstRechargeReward: config.FirstRechargeReward,
|
||||
sevenDayCheckIn: config.SevenDayCheckIn,
|
||||
luckyGift: config.LuckyGift,
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +62,7 @@ func (h *Handler) TaskHandlers() httproutes.TaskHandlers {
|
||||
GetSevenDayCheckInStatus: h.getSevenDayCheckInStatus,
|
||||
SignSevenDayCheckIn: h.signSevenDayCheckIn,
|
||||
ListUserLeaderboards: h.listUserLeaderboards,
|
||||
CheckLuckyGift: h.checkLuckyGift,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,71 @@
|
||||
package activityapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
"hyapp/services/gateway-service/internal/transport/http/httpkit"
|
||||
)
|
||||
|
||||
type luckyGiftCheckRequest struct {
|
||||
RoomID string `json:"room_id"`
|
||||
GiftID string `json:"gift_id"`
|
||||
PoolID string `json:"pool_id"`
|
||||
}
|
||||
|
||||
type luckyGiftCheckData struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Reason string `json:"reason"`
|
||||
RoomID string `json:"room_id"`
|
||||
GiftID string `json:"gift_id"`
|
||||
PoolID string `json:"pool_id"`
|
||||
GiftPrice int64 `json:"gift_price"`
|
||||
RuleVersion int64 `json:"rule_version"`
|
||||
TargetRTPPPM int64 `json:"target_rtp_ppm"`
|
||||
ExperiencePool string `json:"experience_pool"`
|
||||
}
|
||||
|
||||
// checkLuckyGift 只做送礼前资格检查;扣费、抽奖和返奖都必须继续走 room-service 送礼主链路。
|
||||
func (h *Handler) checkLuckyGift(writer http.ResponseWriter, request *http.Request) {
|
||||
if h.luckyGift == nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "upstream service error")
|
||||
return
|
||||
}
|
||||
var body luckyGiftCheckRequest
|
||||
if err := json.NewDecoder(request.Body).Decode(&body); err != nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid request body")
|
||||
return
|
||||
}
|
||||
body.RoomID = strings.TrimSpace(body.RoomID)
|
||||
body.GiftID = strings.TrimSpace(body.GiftID)
|
||||
body.PoolID = strings.TrimSpace(body.PoolID)
|
||||
if body.RoomID == "" || body.GiftID == "" || body.PoolID == "" {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "room_id, gift_id and pool_id are required")
|
||||
return
|
||||
}
|
||||
resp, err := h.luckyGift.CheckLuckyGift(request.Context(), &activityv1.CheckLuckyGiftRequest{
|
||||
Meta: httpkit.ActivityMeta(request),
|
||||
UserId: auth.UserIDFromContext(request.Context()),
|
||||
RoomId: body.RoomID,
|
||||
GiftId: body.GiftID,
|
||||
PoolId: body.PoolID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, luckyGiftCheckData{
|
||||
Enabled: resp.GetEnabled(),
|
||||
Reason: resp.GetReason(),
|
||||
RoomID: body.RoomID,
|
||||
GiftID: resp.GetGiftId(),
|
||||
PoolID: resp.GetPoolId(),
|
||||
GiftPrice: resp.GetGiftPrice(),
|
||||
RuleVersion: resp.GetRuleVersion(),
|
||||
TargetRTPPPM: resp.GetTargetRtpPpm(),
|
||||
ExperiencePool: resp.GetExperiencePool(),
|
||||
})
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package activityapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
activityv1 "hyapp.local/api/proto/activity/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/services/gateway-service/internal/auth"
|
||||
)
|
||||
|
||||
func TestCheckLuckyGiftForwardsEligibilityRequest(t *testing.T) {
|
||||
client := &fakeLuckyGiftClient{resp: &activityv1.CheckLuckyGiftResponse{
|
||||
Enabled: true,
|
||||
Reason: "enabled",
|
||||
GiftId: "rose",
|
||||
PoolId: "super_lucky",
|
||||
GiftPrice: 100,
|
||||
RuleVersion: 3,
|
||||
TargetRtpPpm: 600000,
|
||||
ExperiencePool: "novice",
|
||||
}}
|
||||
handler := New(Config{LuckyGift: client})
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/activities/lucky-gifts/check", strings.NewReader(`{"room_id":"room-1","gift_id":"rose","pool_id":"super_lucky"}`))
|
||||
request = request.WithContext(auth.WithUserID(appcode.WithContext(request.Context(), "lalu"), 42))
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
handler.checkLuckyGift(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if client.last == nil || client.last.GetUserId() != 42 || client.last.GetRoomId() != "room-1" || client.last.GetGiftId() != "rose" || client.last.GetPoolId() != "super_lucky" {
|
||||
t.Fatalf("check request mismatch: %+v", client.last)
|
||||
}
|
||||
var envelope struct {
|
||||
Code string `json:"code"`
|
||||
Data struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
Reason string `json:"reason"`
|
||||
ExperiencePool string `json:"experience_pool"`
|
||||
} `json:"data"`
|
||||
}
|
||||
if err := json.Unmarshal(recorder.Body.Bytes(), &envelope); err != nil {
|
||||
t.Fatalf("decode response: %v", err)
|
||||
}
|
||||
if envelope.Code != "OK" || !envelope.Data.Enabled || envelope.Data.ExperiencePool != "novice" {
|
||||
t.Fatalf("response mismatch: %+v", envelope)
|
||||
}
|
||||
}
|
||||
|
||||
type fakeLuckyGiftClient struct {
|
||||
last *activityv1.CheckLuckyGiftRequest
|
||||
resp *activityv1.CheckLuckyGiftResponse
|
||||
}
|
||||
|
||||
func (c *fakeLuckyGiftClient) CheckLuckyGift(_ context.Context, req *activityv1.CheckLuckyGiftRequest) (*activityv1.CheckLuckyGiftResponse, error) {
|
||||
c.last = req
|
||||
return c.resp, nil
|
||||
}
|
||||
@ -41,6 +41,7 @@ type Handler struct {
|
||||
registrationReward client.RegistrationRewardClient
|
||||
firstRechargeReward client.FirstRechargeRewardClient
|
||||
sevenDayCheckIn client.SevenDayCheckInClient
|
||||
luckyGift client.LuckyGiftClient
|
||||
broadcastClient client.BroadcastClient
|
||||
gameClient client.GameClient
|
||||
appConfigReader appapi.ConfigReader
|
||||
@ -204,6 +205,11 @@ func (h *Handler) SetSevenDayCheckInClient(sevenDayCheckIn client.SevenDayCheckI
|
||||
h.sevenDayCheckIn = sevenDayCheckIn
|
||||
}
|
||||
|
||||
// SetLuckyGiftClient 注入 activity-service 幸运礼物资格检查 client。
|
||||
func (h *Handler) SetLuckyGiftClient(luckyGift client.LuckyGiftClient) {
|
||||
h.luckyGift = luckyGift
|
||||
}
|
||||
|
||||
// SetBroadcastClient 注入 activity-service 播报群成员关系 client。
|
||||
func (h *Handler) SetBroadcastClient(broadcastClient client.BroadcastClient) {
|
||||
h.broadcastClient = broadcastClient
|
||||
|
||||
@ -138,6 +138,7 @@ type TaskHandlers struct {
|
||||
GetSevenDayCheckInStatus http.HandlerFunc
|
||||
SignSevenDayCheckIn http.HandlerFunc
|
||||
ListUserLeaderboards http.HandlerFunc
|
||||
CheckLuckyGift http.HandlerFunc
|
||||
}
|
||||
|
||||
type LevelHandlers struct {
|
||||
@ -343,6 +344,7 @@ func (r routes) registerTaskRoutes() {
|
||||
r.profile("/activities/seven-day-checkin", http.MethodGet, h.GetSevenDayCheckInStatus)
|
||||
r.profile("/activities/seven-day-checkin/sign", http.MethodPost, h.SignSevenDayCheckIn)
|
||||
r.profile("/activities/user-leaderboards", http.MethodGet, h.ListUserLeaderboards)
|
||||
r.profile("/activities/lucky-gifts/check", http.MethodPost, h.CheckLuckyGift)
|
||||
r.profile("/tasks/tabs", http.MethodGet, h.ListTaskTabs)
|
||||
r.profile("/tasks/claim", http.MethodPost, h.ClaimTaskReward)
|
||||
}
|
||||
|
||||
@ -68,6 +68,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
|
||||
RegistrationReward: h.registrationReward,
|
||||
FirstRechargeReward: h.firstRechargeReward,
|
||||
SevenDayCheckIn: h.sevenDayCheckIn,
|
||||
LuckyGift: h.luckyGift,
|
||||
})
|
||||
gameAPI := gameapi.New(gameapi.Config{
|
||||
GameClient: h.gameClient,
|
||||
|
||||
@ -126,16 +126,18 @@ func (s *Service) SendGift(ctx context.Context, req *roomv1.SendGiftRequest) (*r
|
||||
if luckyEnabled {
|
||||
drawResp, err := s.luckyGift.ExecuteLuckyGiftDraw(ctx, &activityv1.ExecuteLuckyGiftDrawRequest{
|
||||
LuckyGift: &activityv1.LuckyGiftMeta{
|
||||
Meta: activityMetaFromRoom(ctx, req.GetMeta()),
|
||||
CommandId: cmd.ID(),
|
||||
UserId: cmd.ActorUserID(),
|
||||
DeviceId: luckyGiftDeviceID(cmd),
|
||||
RoomId: cmd.RoomID(),
|
||||
AnchorId: luckyGiftAnchorID(roomMeta),
|
||||
GiftId: cmd.GiftID,
|
||||
CoinSpent: billing.GetCoinSpent(),
|
||||
PaidAtMs: now.UTC().UnixMilli(),
|
||||
PoolId: cmd.PoolID,
|
||||
Meta: activityMetaFromRoom(ctx, req.GetMeta()),
|
||||
CommandId: cmd.ID(),
|
||||
UserId: cmd.ActorUserID(),
|
||||
TargetUserId: cmd.TargetUserID,
|
||||
DeviceId: luckyGiftDeviceID(cmd),
|
||||
RoomId: cmd.RoomID(),
|
||||
AnchorId: luckyGiftAnchorID(roomMeta),
|
||||
GiftId: cmd.GiftID,
|
||||
GiftCount: cmd.GiftCount,
|
||||
CoinSpent: billing.GetCoinSpent(),
|
||||
PaidAtMs: now.UTC().UnixMilli(),
|
||||
PoolId: cmd.PoolID,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@ -553,6 +553,27 @@ type TaskRewardReceipt struct {
|
||||
GrantedAtMS int64
|
||||
}
|
||||
|
||||
// LuckyGiftRewardCommand 是 activity-service 用抽奖 draw_id 发起的 COIN 入账命令。
|
||||
type LuckyGiftRewardCommand struct {
|
||||
AppCode string
|
||||
CommandID string
|
||||
TargetUserID int64
|
||||
Amount int64
|
||||
DrawID string
|
||||
RoomID string
|
||||
GiftID string
|
||||
PoolID string
|
||||
Reason string
|
||||
}
|
||||
|
||||
// LuckyGiftRewardReceipt 是幸运礼物返奖入账后的稳定回执。
|
||||
type LuckyGiftRewardReceipt struct {
|
||||
TransactionID string
|
||||
Balance AssetBalance
|
||||
Amount int64
|
||||
GrantedAtMS int64
|
||||
}
|
||||
|
||||
// GameCoinChangeCommand 是 game-service 对钱包发起的游戏专用金币改账命令。
|
||||
type GameCoinChangeCommand struct {
|
||||
AppCode string
|
||||
|
||||
@ -23,6 +23,7 @@ type Repository interface {
|
||||
AdminCreditCoinSellerStock(ctx context.Context, command ledger.CoinSellerStockCreditCommand) (ledger.CoinSellerStockCreditReceipt, error)
|
||||
TransferCoinFromSeller(ctx context.Context, command ledger.CoinSellerTransferCommand) (ledger.CoinSellerTransferReceipt, error)
|
||||
CreditTaskReward(ctx context.Context, command ledger.TaskRewardCommand) (ledger.TaskRewardReceipt, error)
|
||||
CreditLuckyGiftReward(ctx context.Context, command ledger.LuckyGiftRewardCommand) (ledger.LuckyGiftRewardReceipt, error)
|
||||
ApplyGameCoinChange(ctx context.Context, command ledger.GameCoinChangeCommand) (ledger.GameCoinChangeReceipt, error)
|
||||
GetRedPacketConfig(ctx context.Context, appCode string) (ledger.RedPacketConfig, error)
|
||||
UpdateRedPacketConfig(ctx context.Context, config ledger.RedPacketConfig) (ledger.RedPacketConfig, error)
|
||||
@ -269,6 +270,28 @@ func (s *Service) CreditTaskReward(ctx context.Context, command ledger.TaskRewar
|
||||
return s.repository.CreditTaskReward(ctx, command)
|
||||
}
|
||||
|
||||
// CreditLuckyGiftReward 发放幸运礼物中奖金币;抽奖资格和金额已由 activity-service 决策,钱包只做幂等入账。
|
||||
func (s *Service) CreditLuckyGiftReward(ctx context.Context, command ledger.LuckyGiftRewardCommand) (ledger.LuckyGiftRewardReceipt, error) {
|
||||
if command.CommandID == "" || command.TargetUserID <= 0 || command.Amount <= 0 || command.DrawID == "" || command.RoomID == "" || command.GiftID == "" || command.PoolID == "" {
|
||||
return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.InvalidArgument, "lucky gift reward command is incomplete")
|
||||
}
|
||||
command.Reason = strings.TrimSpace(command.Reason)
|
||||
if command.Reason == "" {
|
||||
return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.InvalidArgument, "reason is required")
|
||||
}
|
||||
if s.repository == nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||||
}
|
||||
command.AppCode = appcode.Normalize(command.AppCode)
|
||||
command.DrawID = strings.TrimSpace(command.DrawID)
|
||||
command.RoomID = strings.TrimSpace(command.RoomID)
|
||||
command.GiftID = strings.TrimSpace(command.GiftID)
|
||||
command.PoolID = strings.TrimSpace(command.PoolID)
|
||||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||||
|
||||
return s.repository.CreditLuckyGiftReward(ctx, command)
|
||||
}
|
||||
|
||||
// ApplyGameCoinChange 是游戏平台唯一的 COIN 改账入口,方向由 op_type 控制。
|
||||
func (s *Service) ApplyGameCoinChange(ctx context.Context, command ledger.GameCoinChangeCommand) (ledger.GameCoinChangeReceipt, error) {
|
||||
if command.CommandID == "" || command.UserID <= 0 || command.PlatformCode == "" || command.GameID == "" || command.ProviderOrderID == "" {
|
||||
|
||||
@ -519,6 +519,43 @@ func TestCreditTaskRewardIsIdempotent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreditLuckyGiftRewardIsIdempotent 验证幸运礼物返奖只按 draw_id 派一次,并产出余额通知事实。
|
||||
func TestCreditLuckyGiftRewardIsIdempotent(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
svc := walletservice.New(repository)
|
||||
command := ledger.LuckyGiftRewardCommand{
|
||||
CommandID: "lucky_reward:lucky_draw_1",
|
||||
TargetUserID: 21002,
|
||||
Amount: 188,
|
||||
DrawID: "lucky_draw_1",
|
||||
RoomID: "room-1",
|
||||
GiftID: "rose",
|
||||
PoolID: "super_lucky",
|
||||
Reason: "lucky_gift_reward",
|
||||
}
|
||||
|
||||
first, err := svc.CreditLuckyGiftReward(context.Background(), command)
|
||||
if err != nil {
|
||||
t.Fatalf("CreditLuckyGiftReward failed: %v", err)
|
||||
}
|
||||
second, err := svc.CreditLuckyGiftReward(context.Background(), command)
|
||||
if err != nil {
|
||||
t.Fatalf("CreditLuckyGiftReward retry failed: %v", err)
|
||||
}
|
||||
if first.TransactionID == "" || first.TransactionID != second.TransactionID || second.Balance.AvailableAmount != 188 {
|
||||
t.Fatalf("lucky reward receipt mismatch: first=%+v second=%+v", first, second)
|
||||
}
|
||||
if got := repository.CountRows("wallet_transactions", "command_id = ? AND biz_type = ?", command.CommandID, "lucky_gift_reward"); got != 1 {
|
||||
t.Fatalf("lucky reward should write one transaction, got %d", got)
|
||||
}
|
||||
if got := repository.CountRows("wallet_outbox", "transaction_id = ? AND event_type = ?", first.TransactionID, "WalletBalanceChanged"); got != 1 {
|
||||
t.Fatalf("lucky reward should write one balance change event, got %d", got)
|
||||
}
|
||||
if got := repository.CountRows("wallet_outbox", "transaction_id = ? AND event_type = ?", first.TransactionID, "WalletLuckyGiftRewardCredited"); got != 1 {
|
||||
t.Fatalf("lucky reward should write one reward fact event, got %d", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestTransferCoinFromSellerMovesDedicatedAssetToPlayerCoin 验证币商专用金币和玩家普通金币不会混账。
|
||||
func TestTransferCoinFromSellerMovesDedicatedAssetToPlayerCoin(t *testing.T) {
|
||||
repository := mysqltest.NewRepository(t)
|
||||
|
||||
@ -25,6 +25,7 @@ const (
|
||||
bizTypeGiftDebit = "gift_debit"
|
||||
bizTypeManualCredit = "manual_credit"
|
||||
bizTypeTaskReward = "task_reward"
|
||||
bizTypeLuckyGiftReward = "lucky_gift_reward"
|
||||
bizTypeCoinSellerTransfer = "coin_seller_transfer"
|
||||
bizTypeCoinSellerStockPurchase = "coin_seller_stock_purchase"
|
||||
bizTypeCoinSellerCoinCompensation = "coin_seller_coin_compensation"
|
||||
@ -534,6 +535,80 @@ func (r *Repository) CreditTaskReward(ctx context.Context, command ledger.TaskRe
|
||||
return receiptFromTaskRewardMetadata(transactionID, metadata), nil
|
||||
}
|
||||
|
||||
// CreditLuckyGiftReward 在同一事务里完成幸运礼物中奖 COIN 入账、交易分录和钱包 outbox。
|
||||
func (r *Repository) CreditLuckyGiftReward(ctx context.Context, command ledger.LuckyGiftRewardCommand) (ledger.LuckyGiftRewardReceipt, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
ctx = contextWithCommandApp(ctx, command.AppCode)
|
||||
command.AppCode = appcode.FromContext(ctx)
|
||||
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
requestHash := luckyGiftRewardRequestHash(command)
|
||||
if txRow, exists, err := r.lookupTransaction(ctx, tx, command.CommandID, requestHash, bizTypeLuckyGiftReward); err != nil || exists {
|
||||
if err != nil || !exists {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
return r.receiptForLuckyGiftRewardTransaction(ctx, tx, txRow.TransactionID)
|
||||
}
|
||||
|
||||
nowMs := time.Now().UnixMilli()
|
||||
account, err := r.lockAccount(ctx, tx, command.TargetUserID, ledger.AssetCoin, true, nowMs)
|
||||
if err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
transactionID := transactionID(command.AppCode, command.CommandID)
|
||||
balanceAfter := account.AvailableAmount + command.Amount
|
||||
metadata := luckyGiftRewardMetadata{
|
||||
AppCode: command.AppCode,
|
||||
TargetUserID: command.TargetUserID,
|
||||
AssetType: ledger.AssetCoin,
|
||||
Amount: command.Amount,
|
||||
DrawID: command.DrawID,
|
||||
RoomID: command.RoomID,
|
||||
GiftID: command.GiftID,
|
||||
PoolID: command.PoolID,
|
||||
Reason: command.Reason,
|
||||
BalanceAfter: balanceAfter,
|
||||
GrantedAtMS: nowMs,
|
||||
}
|
||||
if err := r.insertTransaction(ctx, tx, transactionID, command.CommandID, bizTypeLuckyGiftReward, requestHash, command.DrawID, metadata, nowMs); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
if err := r.applyAccountDelta(ctx, tx, account, command.Amount, 0, nowMs); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
if err := r.insertEntry(ctx, tx, walletEntry{
|
||||
TransactionID: transactionID,
|
||||
UserID: command.TargetUserID,
|
||||
AssetType: ledger.AssetCoin,
|
||||
AvailableDelta: command.Amount,
|
||||
FrozenDelta: 0,
|
||||
AvailableAfter: balanceAfter,
|
||||
FrozenAfter: account.FrozenAmount,
|
||||
RoomID: command.RoomID,
|
||||
CreatedAtMS: nowMs,
|
||||
}); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
if err := r.insertWalletOutbox(ctx, tx, []walletOutboxEvent{
|
||||
balanceChangedEvent(transactionID, command.CommandID, command.TargetUserID, ledger.AssetCoin, command.Amount, 0, balanceAfter, account.FrozenAmount, account.Version+1, metadata, nowMs),
|
||||
luckyGiftRewardCreditedEvent(transactionID, command.CommandID, metadata, nowMs),
|
||||
}); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
|
||||
return receiptFromLuckyGiftRewardMetadata(transactionID, metadata), nil
|
||||
}
|
||||
|
||||
// ApplyGameCoinChange 在同一事务内完成游戏 COIN 改账、分录和 outbox。
|
||||
func (r *Repository) ApplyGameCoinChange(ctx context.Context, command ledger.GameCoinChangeCommand) (ledger.GameCoinChangeReceipt, error) {
|
||||
if r == nil || r.db == nil {
|
||||
@ -1548,6 +1623,20 @@ type taskRewardMetadata struct {
|
||||
GrantedAtMS int64 `json:"granted_at_ms"`
|
||||
}
|
||||
|
||||
type luckyGiftRewardMetadata struct {
|
||||
AppCode string `json:"app_code"`
|
||||
TargetUserID int64 `json:"target_user_id"`
|
||||
AssetType string `json:"asset_type"`
|
||||
Amount int64 `json:"amount"`
|
||||
DrawID string `json:"draw_id"`
|
||||
RoomID string `json:"room_id"`
|
||||
GiftID string `json:"gift_id"`
|
||||
PoolID string `json:"pool_id"`
|
||||
Reason string `json:"reason"`
|
||||
BalanceAfter int64 `json:"balance_after"`
|
||||
GrantedAtMS int64 `json:"granted_at_ms"`
|
||||
}
|
||||
|
||||
type gameCoinMetadata struct {
|
||||
AppCode string `json:"app_code"`
|
||||
UserID int64 `json:"user_id"`
|
||||
@ -1654,6 +1743,38 @@ func receiptFromTaskRewardMetadata(transactionID string, metadata taskRewardMeta
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repository) receiptForLuckyGiftRewardTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.LuckyGiftRewardReceipt, error) {
|
||||
var metadataJSON string
|
||||
if err := tx.QueryRowContext(ctx,
|
||||
`SELECT COALESCE(CAST(metadata_json AS CHAR), '{}')
|
||||
FROM wallet_transactions
|
||||
WHERE app_code = ? AND transaction_id = ?`,
|
||||
appcode.FromContext(ctx),
|
||||
transactionID,
|
||||
).Scan(&metadataJSON); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
var metadata luckyGiftRewardMetadata
|
||||
if err := json.Unmarshal([]byte(metadataJSON), &metadata); err != nil {
|
||||
return ledger.LuckyGiftRewardReceipt{}, err
|
||||
}
|
||||
return receiptFromLuckyGiftRewardMetadata(transactionID, metadata), nil
|
||||
}
|
||||
|
||||
func receiptFromLuckyGiftRewardMetadata(transactionID string, metadata luckyGiftRewardMetadata) ledger.LuckyGiftRewardReceipt {
|
||||
return ledger.LuckyGiftRewardReceipt{
|
||||
TransactionID: transactionID,
|
||||
Balance: ledger.AssetBalance{
|
||||
AppCode: metadata.AppCode,
|
||||
UserID: metadata.TargetUserID,
|
||||
AssetType: metadata.AssetType,
|
||||
AvailableAmount: metadata.BalanceAfter,
|
||||
},
|
||||
Amount: metadata.Amount,
|
||||
GrantedAtMS: metadata.GrantedAtMS,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *Repository) receiptForGameTransaction(ctx context.Context, tx *sql.Tx, transactionID string) (ledger.GameCoinChangeReceipt, error) {
|
||||
var metadataJSON string
|
||||
if err := tx.QueryRowContext(ctx,
|
||||
@ -1836,6 +1957,32 @@ func taskRewardCreditedEvent(transactionID string, commandID string, metadata ta
|
||||
}
|
||||
}
|
||||
|
||||
func luckyGiftRewardCreditedEvent(transactionID string, commandID string, metadata luckyGiftRewardMetadata, nowMs int64) walletOutboxEvent {
|
||||
return walletOutboxEvent{
|
||||
EventID: eventID(transactionID, "WalletLuckyGiftRewardCredited", metadata.TargetUserID, ledger.AssetCoin),
|
||||
EventType: "WalletLuckyGiftRewardCredited",
|
||||
TransactionID: transactionID,
|
||||
CommandID: commandID,
|
||||
UserID: metadata.TargetUserID,
|
||||
AssetType: ledger.AssetCoin,
|
||||
AvailableDelta: metadata.Amount,
|
||||
FrozenDelta: 0,
|
||||
Payload: map[string]any{
|
||||
"transaction_id": transactionID,
|
||||
"command_id": commandID,
|
||||
"user_id": metadata.TargetUserID,
|
||||
"draw_id": metadata.DrawID,
|
||||
"room_id": metadata.RoomID,
|
||||
"gift_id": metadata.GiftID,
|
||||
"pool_id": metadata.PoolID,
|
||||
"amount": metadata.Amount,
|
||||
"reason": metadata.Reason,
|
||||
"created_at_ms": nowMs,
|
||||
},
|
||||
CreatedAtMS: nowMs,
|
||||
}
|
||||
}
|
||||
|
||||
func coinSellerStockCreditedEvent(transactionID string, commandID string, metadata coinSellerStockMetadata, nowMs int64) walletOutboxEvent {
|
||||
eventType := "WalletCoinSellerCoinCompensated"
|
||||
if metadata.StockType == ledger.StockTypeUSDTPurchase {
|
||||
@ -1965,6 +2112,19 @@ func taskRewardRequestHash(command ledger.TaskRewardCommand) string {
|
||||
))
|
||||
}
|
||||
|
||||
func luckyGiftRewardRequestHash(command ledger.LuckyGiftRewardCommand) string {
|
||||
return stableHash(fmt.Sprintf("lucky_gift_reward|%s|%d|%d|%s|%s|%s|%s|%s",
|
||||
appcode.Normalize(command.AppCode),
|
||||
command.TargetUserID,
|
||||
command.Amount,
|
||||
strings.TrimSpace(command.DrawID),
|
||||
strings.TrimSpace(command.RoomID),
|
||||
strings.TrimSpace(command.GiftID),
|
||||
strings.TrimSpace(command.PoolID),
|
||||
strings.TrimSpace(command.Reason),
|
||||
))
|
||||
}
|
||||
|
||||
func gameBizTypeAndDelta(opType string, coinAmount int64) (string, int64, error) {
|
||||
switch ledger.NormalizeGameOpType(opType) {
|
||||
case ledger.GameOpDebit:
|
||||
|
||||
@ -651,6 +651,38 @@ func (s *Server) CreditTaskReward(ctx context.Context, req *walletv1.CreditTaskR
|
||||
}, nil
|
||||
}
|
||||
|
||||
// CreditLuckyGiftReward 处理 activity-service 幸运礼物抽奖 outbox 的中奖金币入账。
|
||||
func (s *Server) CreditLuckyGiftReward(ctx context.Context, req *walletv1.CreditLuckyGiftRewardRequest) (*walletv1.CreditLuckyGiftRewardResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
||||
receipt, err := s.svc.CreditLuckyGiftReward(ctx, ledger.LuckyGiftRewardCommand{
|
||||
AppCode: req.GetAppCode(),
|
||||
CommandID: req.GetCommandId(),
|
||||
TargetUserID: req.GetTargetUserId(),
|
||||
Amount: req.GetAmount(),
|
||||
DrawID: req.GetDrawId(),
|
||||
RoomID: req.GetRoomId(),
|
||||
GiftID: req.GetGiftId(),
|
||||
PoolID: req.GetPoolId(),
|
||||
Reason: req.GetReason(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
|
||||
return &walletv1.CreditLuckyGiftRewardResponse{
|
||||
TransactionId: receipt.TransactionID,
|
||||
Amount: receipt.Amount,
|
||||
GrantedAtMs: receipt.GrantedAtMS,
|
||||
Balance: &walletv1.AssetBalance{
|
||||
AppCode: receipt.Balance.AppCode,
|
||||
AssetType: receipt.Balance.AssetType,
|
||||
AvailableAmount: receipt.Balance.AvailableAmount,
|
||||
FrozenAmount: receipt.Balance.FrozenAmount,
|
||||
Version: receipt.Balance.Version,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ApplyGameCoinChange 处理 game-service 发起的游戏专用金币改账。
|
||||
func (s *Server) ApplyGameCoinChange(ctx context.Context, req *walletv1.ApplyGameCoinChangeRequest) (*walletv1.ApplyGameCoinChangeResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user