三方支付链接
This commit is contained in:
parent
6fd0f03895
commit
f8e34770d3
@ -472,6 +472,8 @@ type RoomUserJoined struct {
|
||||
EntryVehicle *RoomEntryVehicleSnapshot `protobuf:"bytes,4,opt,name=entry_vehicle,json=entryVehicle,proto3" json:"entry_vehicle,omitempty"`
|
||||
CountryId int64 `protobuf:"varint,5,opt,name=country_id,json=countryId,proto3" json:"country_id,omitempty"`
|
||||
RegionId int64 `protobuf:"varint,6,opt,name=region_id,json=regionId,proto3" json:"region_id,omitempty"`
|
||||
// is_robot 标记本次进房来自房间机器人调度,统计服务必须跳过活跃用户口径。
|
||||
IsRobot bool `protobuf:"varint,7,opt,name=is_robot,json=isRobot,proto3" json:"is_robot,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoomUserJoined) Reset() {
|
||||
@ -546,6 +548,13 @@ func (x *RoomUserJoined) GetRegionId() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RoomUserJoined) GetIsRobot() bool {
|
||||
if x != nil {
|
||||
return x.IsRobot
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// RoomUserLeft 表达用户离房成功。
|
||||
type RoomUserLeft struct {
|
||||
state protoimpl.MessageState
|
||||
@ -1233,6 +1242,16 @@ type RoomGiftSent struct {
|
||||
SyntheticLuckyGift bool `protobuf:"varint,21,opt,name=synthetic_lucky_gift,json=syntheticLuckyGift,proto3" json:"synthetic_lucky_gift,omitempty"`
|
||||
// real_room_robot_gift 标记真人房机器人送出的真实热度礼物,用于 Databi 单独统计机器人投放价值。
|
||||
RealRoomRobotGift bool `protobuf:"varint,22,opt,name=real_room_robot_gift,json=realRoomRobotGift,proto3" json:"real_room_robot_gift,omitempty"`
|
||||
// sender_name 是送礼入口固化的展示昵称,只用于客户端 IM 展示兜底,不作为用户主资料事实。
|
||||
SenderName string `protobuf:"bytes,23,opt,name=sender_name,json=senderName,proto3" json:"sender_name,omitempty"`
|
||||
SenderAvatar string `protobuf:"bytes,24,opt,name=sender_avatar,json=senderAvatar,proto3" json:"sender_avatar,omitempty"`
|
||||
SenderDisplayUserId string `protobuf:"bytes,25,opt,name=sender_display_user_id,json=senderDisplayUserId,proto3" json:"sender_display_user_id,omitempty"`
|
||||
SenderPrettyDisplayUserId string `protobuf:"bytes,26,opt,name=sender_pretty_display_user_id,json=senderPrettyDisplayUserId,proto3" json:"sender_pretty_display_user_id,omitempty"`
|
||||
// receiver_nickname 是收礼目标在送礼瞬间的展示昵称;字段名匹配 Flutter 已有解析逻辑。
|
||||
ReceiverNickname string `protobuf:"bytes,27,opt,name=receiver_nickname,json=receiverNickname,proto3" json:"receiver_nickname,omitempty"`
|
||||
ReceiverAvatar string `protobuf:"bytes,28,opt,name=receiver_avatar,json=receiverAvatar,proto3" json:"receiver_avatar,omitempty"`
|
||||
ReceiverDisplayUserId string `protobuf:"bytes,29,opt,name=receiver_display_user_id,json=receiverDisplayUserId,proto3" json:"receiver_display_user_id,omitempty"`
|
||||
ReceiverPrettyDisplayUserId string `protobuf:"bytes,30,opt,name=receiver_pretty_display_user_id,json=receiverPrettyDisplayUserId,proto3" json:"receiver_pretty_display_user_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) Reset() {
|
||||
@ -1419,6 +1438,62 @@ func (x *RoomGiftSent) GetRealRoomRobotGift() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetSenderName() string {
|
||||
if x != nil {
|
||||
return x.SenderName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetSenderAvatar() string {
|
||||
if x != nil {
|
||||
return x.SenderAvatar
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetSenderDisplayUserId() string {
|
||||
if x != nil {
|
||||
return x.SenderDisplayUserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetSenderPrettyDisplayUserId() string {
|
||||
if x != nil {
|
||||
return x.SenderPrettyDisplayUserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetReceiverNickname() string {
|
||||
if x != nil {
|
||||
return x.ReceiverNickname
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetReceiverAvatar() string {
|
||||
if x != nil {
|
||||
return x.ReceiverAvatar
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetReceiverDisplayUserId() string {
|
||||
if x != nil {
|
||||
return x.ReceiverDisplayUserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RoomGiftSent) GetReceiverPrettyDisplayUserId() string {
|
||||
if x != nil {
|
||||
return x.ReceiverPrettyDisplayUserId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// RoomRobotLuckyGiftDrawn 是机器人房间专用幸运礼物展示事件。
|
||||
// 它复用客户端 lucky_gift_drawn 表现协议,但不代表真实奖池抽奖和钱包返奖事实。
|
||||
type RoomRobotLuckyGiftDrawn struct {
|
||||
@ -2353,7 +2428,7 @@ var file_proto_events_room_v1_events_proto_rawDesc = []byte{
|
||||
0x01, 0x28, 0x09, 0x52, 0x0d, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74,
|
||||
0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x65, 0x78, 0x70, 0x69, 0x72, 0x65, 0x73, 0x5f, 0x61, 0x74,
|
||||
0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x65, 0x78, 0x70, 0x69, 0x72,
|
||||
0x65, 0x73, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xfa, 0x01, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x55,
|
||||
0x65, 0x73, 0x41, 0x74, 0x4d, 0x73, 0x22, 0x95, 0x02, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x55,
|
||||
0x73, 0x65, 0x72, 0x4a, 0x6f, 0x69, 0x6e, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65,
|
||||
0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72,
|
||||
0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x6f, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
|
||||
@ -2369,309 +2444,335 @@ var file_proto_events_room_v1_events_proto_rawDesc = []byte{
|
||||
0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x64, 0x22, 0x27, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4c,
|
||||
0x65, 0x66, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x48, 0x0a, 0x0a,
|
||||
0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x22, 0xd8, 0x03, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x4d,
|
||||
0x69, 0x63, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a,
|
||||
0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65,
|
||||
0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x73, 0x65, 0x61, 0x74,
|
||||
0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x61, 0x74,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x74, 0x6f, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x06, 0x74, 0x6f, 0x53, 0x65, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x12, 0x24, 0x0a, 0x0e, 0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65,
|
||||
0x73, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x73, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||
0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65,
|
||||
0x61, 0x73, 0x6f, 0x6e, 0x12, 0x2e, 0x0a, 0x13, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f,
|
||||
0x64, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x11, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69,
|
||||
0x6e, 0x65, 0x4d, 0x73, 0x12, 0x31, 0x0a, 0x15, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f,
|
||||
0x65, 0x76, 0x65, 0x6e, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x0a, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x12, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e,
|
||||
0x74, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x63, 0x5f, 0x6d,
|
||||
0x75, 0x74, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x69, 0x63, 0x4d,
|
||||
0x75, 0x74, 0x65, 0x64, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x73, 0x74, 0x61,
|
||||
0x74, 0x75, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x53,
|
||||
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
||||
0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x22, 0x68, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74,
|
||||
0x4c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61,
|
||||
0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65,
|
||||
0x61, 0x74, 0x5f, 0x6e, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61,
|
||||
0x74, 0x4e, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x22, 0x56, 0x0a, 0x16, 0x52,
|
||||
0x6f, 0x6f, 0x6d, 0x43, 0x68, 0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x43, 0x68,
|
||||
0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x18,
|
||||
0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x22, 0x27,
|
||||
0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x65, 0x66, 0x74, 0x12, 0x17,
|
||||
0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x48, 0x0a, 0x0a, 0x52, 0x6f, 0x6f, 0x6d, 0x43,
|
||||
0x6c, 0x6f, 0x73, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75,
|
||||
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61,
|
||||
0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f,
|
||||
0x6e, 0x22, 0xd8, 0x03, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x43, 0x68, 0x61,
|
||||
0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74,
|
||||
0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67,
|
||||
0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b,
|
||||
0x0a, 0x09, 0x66, 0x72, 0x6f, 0x6d, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x08, 0x66, 0x72, 0x6f, 0x6d, 0x53, 0x65, 0x61, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74,
|
||||
0x6f, 0x5f, 0x73, 0x65, 0x61, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x74, 0x6f,
|
||||
0x53, 0x65, 0x61, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x24, 0x0a, 0x0e,
|
||||
0x6d, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x06,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x6d, 0x69, 0x63, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x73, 0x74,
|
||||
0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x70, 0x75, 0x62, 0x6c, 0x69,
|
||||
0x73, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f,
|
||||
0x6e, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12,
|
||||
0x2e, 0x0a, 0x13, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x64, 0x65, 0x61, 0x64, 0x6c,
|
||||
0x69, 0x6e, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x11, 0x70, 0x75,
|
||||
0x62, 0x6c, 0x69, 0x73, 0x68, 0x44, 0x65, 0x61, 0x64, 0x6c, 0x69, 0x6e, 0x65, 0x4d, 0x73, 0x12,
|
||||
0x31, 0x0a, 0x15, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x5f, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12,
|
||||
0x70, 0x75, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x54, 0x69, 0x6d, 0x65,
|
||||
0x4d, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x69, 0x63, 0x5f, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18,
|
||||
0x0b, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x6d, 0x69, 0x63, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12,
|
||||
0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x0c,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x61, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73,
|
||||
0x12, 0x2a, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x5f,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x74, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x47, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x68, 0x0a, 0x11,
|
||||
0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x69, 0x63, 0x53, 0x65, 0x61, 0x74, 0x4c, 0x6f, 0x63, 0x6b, 0x65,
|
||||
0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55,
|
||||
0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x65, 0x61, 0x74, 0x5f, 0x6e, 0x6f,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x73, 0x65, 0x61, 0x74, 0x4e, 0x6f, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x22, 0x56, 0x0a, 0x16, 0x52, 0x6f, 0x6f, 0x6d, 0x43, 0x68,
|
||||
0x61, 0x74, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64,
|
||||
0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73,
|
||||
0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x7d,
|
||||
0x0a, 0x13, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x68,
|
||||
0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75,
|
||||
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61,
|
||||
0x62, 0x6c, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62,
|
||||
0x6c, 0x65, 0x64, 0x22, 0x7d, 0x0a, 0x13, 0x52, 0x6f, 0x6f, 0x6d, 0x50, 0x61, 0x73, 0x73, 0x77,
|
||||
0x6f, 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63,
|
||||
0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16,
|
||||
0x0a, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c,
|
||||
0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x22, 0x76, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43,
|
||||
0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f,
|
||||
0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x6c, 0x6f, 0x63, 0x6b, 0x65,
|
||||
0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69,
|
||||
0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x76, 0x0a,
|
||||
0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f,
|
||||
0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55,
|
||||
0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x65,
|
||||
0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x65, 0x6e,
|
||||
0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x6f, 0x0a, 0x0d, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65,
|
||||
0x72, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61,
|
||||
0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64,
|
||||
0x12, 0x18, 0x0a, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x07, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x22, 0x6f, 0x0a, 0x0d, 0x52, 0x6f,
|
||||
0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4d, 0x75, 0x74, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61,
|
||||
0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12,
|
||||
0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55,
|
||||
0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x22, 0x5a, 0x0a, 0x0e, 0x52,
|
||||
0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a,
|
||||
0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0x5c, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x55,
|
||||
0x73, 0x65, 0x72, 0x55, 0x6e, 0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61,
|
||||
0x63, 0x74, 0x6f, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12,
|
||||
0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55,
|
||||
0x73, 0x65, 0x72, 0x49, 0x64, 0x22, 0xbc, 0x06, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x69,
|
||||
0x66, 0x74, 0x53, 0x65, 0x6e, 0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72,
|
||||
0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c,
|
||||
0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x22, 0x5a, 0x0a, 0x0e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73,
|
||||
0x65, 0x72, 0x4b, 0x69, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f,
|
||||
0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0b, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e,
|
||||
0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72,
|
||||
0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67,
|
||||
0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69,
|
||||
0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
|
||||
0x67, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c,
|
||||
0x6c, 0x69, 0x6e, 0x67, 0x5f, 0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65,
|
||||
0x63, 0x65, 0x69, 0x70, 0x74, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62,
|
||||
0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f,
|
||||
0x6e, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63,
|
||||
0x6f, 0x69, 0x6e, 0x5f, 0x73, 0x70, 0x65, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x09, 0x63, 0x6f, 0x69, 0x6e, 0x53, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f,
|
||||
0x75, 0x6e, 0x74, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09,
|
||||
0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65,
|
||||
0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x74,
|
||||
0x79, 0x70, 0x65, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
|
||||
0x67, 0x69, 0x66, 0x74, 0x54, 0x79, 0x70, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x10,
|
||||
0x63, 0x70, 0x5f, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65,
|
||||
0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x63, 0x70, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x6e,
|
||||
0x61, 0x6d, 0x65, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e,
|
||||
0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x63, 0x6f, 0x6e,
|
||||
0x5f, 0x75, 0x72, 0x6c, 0x18, 0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x69, 0x66, 0x74,
|
||||
0x49, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x66, 0x74, 0x5f,
|
||||
0x61, 0x6e, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x11, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x66, 0x74, 0x41, 0x6e, 0x69, 0x6d, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
|
||||
0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x47, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x12, 0x2a, 0x0a, 0x11, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74,
|
||||
0x5f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x67, 0x69,
|
||||
0x66, 0x74, 0x45, 0x66, 0x66, 0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x22, 0x0a,
|
||||
0x0d, 0x69, 0x73, 0x5f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x18, 0x14,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x47, 0x69, 0x66,
|
||||
0x74, 0x12, 0x30, 0x0a, 0x14, 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x5f, 0x6c,
|
||||
0x75, 0x63, 0x6b, 0x79, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x12, 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x4c, 0x75, 0x63, 0x6b, 0x79, 0x47,
|
||||
0x69, 0x66, 0x74, 0x12, 0x2f, 0x0a, 0x14, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x6f, 0x6d,
|
||||
0x5f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28,
|
||||
0x08, 0x52, 0x11, 0x72, 0x65, 0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74,
|
||||
0x47, 0x69, 0x66, 0x74, 0x22, 0xf7, 0x04, 0x0a, 0x17, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62,
|
||||
0x6f, 0x74, 0x4c, 0x75, 0x63, 0x6b, 0x79, 0x47, 0x69, 0x66, 0x74, 0x44, 0x72, 0x61, 0x77, 0x6e,
|
||||
0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x06, 0x64, 0x72, 0x61, 0x77, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d,
|
||||
0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63,
|
||||
0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64,
|
||||
0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24,
|
||||
0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73,
|
||||
0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a,
|
||||
0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28,
|
||||
0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07,
|
||||
0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70,
|
||||
0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c,
|
||||
0x69, 0x65, 0x72, 0x5f, 0x70, 0x70, 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d,
|
||||
0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x70, 0x6d, 0x12, 0x2a, 0x0a, 0x11,
|
||||
0x62, 0x61, 0x73, 0x65, 0x5f, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x69, 0x6e,
|
||||
0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x77,
|
||||
0x61, 0x72, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x72, 0x6f, 0x6f, 0x6d,
|
||||
0x5f, 0x61, 0x74, 0x6d, 0x6f, 0x73, 0x70, 0x68, 0x65, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x77, 0x61,
|
||||
0x72, 0x64, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19,
|
||||
0x72, 0x6f, 0x6f, 0x6d, 0x41, 0x74, 0x6d, 0x6f, 0x73, 0x70, 0x68, 0x65, 0x72, 0x65, 0x52, 0x65,
|
||||
0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x61, 0x63, 0x74,
|
||||
0x69, 0x76, 0x69, 0x74, 0x79, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x69, 0x64, 0x79, 0x5f, 0x63, 0x6f,
|
||||
0x69, 0x6e, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x61, 0x63, 0x74, 0x69, 0x76,
|
||||
0x69, 0x74, 0x79, 0x53, 0x75, 0x62, 0x73, 0x69, 0x64, 0x79, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12,
|
||||
0x34, 0x0a, 0x16, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x72, 0x65, 0x77,
|
||||
0x61, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x14, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64,
|
||||
0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64,
|
||||
0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73,
|
||||
0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0e,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67,
|
||||
0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x72, 0x6f, 0x62, 0x6f,
|
||||
0x74, 0x18, 0x0f, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74,
|
||||
0x12, 0x1c, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x18, 0x10, 0x20,
|
||||
0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x22, 0x4a,
|
||||
0x0a, 0x0f, 0x52, 0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65,
|
||||
0x64, 0x12, 0x14, 0x0a, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65,
|
||||
0x6e, 0x74, 0x5f, 0x68, 0x65, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63,
|
||||
0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x74, 0x22, 0x5f, 0x0a, 0x0f, 0x52, 0x6f,
|
||||
0x6f, 0x6d, 0x52, 0x61, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06,
|
||||
0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x94, 0x02, 0x0a, 0x15,
|
||||
0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64,
|
||||
0x47, 0x72, 0x61, 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f,
|
||||
0x72, 0x6f, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x77, 0x61,
|
||||
0x72, 0x64, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12,
|
||||
0x24, 0x0a, 0x0e, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49,
|
||||
0x74, 0x65, 0x6d, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63,
|
||||
0x65, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49,
|
||||
0x64, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79,
|
||||
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c,
|
||||
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12,
|
||||
0x19, 0x0a, 0x08, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x07, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74,
|
||||
0x75, 0x73, 0x22, 0xeb, 0x03, 0x0a, 0x15, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65,
|
||||
0x74, 0x46, 0x75, 0x65, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76,
|
||||
0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x09, 0x61, 0x64, 0x64, 0x65, 0x64, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x30,
|
||||
0x0a, 0x14, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x65,
|
||||
0x64, 0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x65, 0x66,
|
||||
0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x41, 0x64, 0x64, 0x65, 0x64, 0x46, 0x75, 0x65, 0x6c,
|
||||
0x12, 0x23, 0x0a, 0x0d, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x66, 0x75, 0x65,
|
||||
0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f,
|
||||
0x77, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74,
|
||||
0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x75, 0x72,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x75, 0x65, 0x6c,
|
||||
0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0d, 0x66, 0x75, 0x65, 0x6c, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12,
|
||||
0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x74,
|
||||
0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65,
|
||||
0x73, 0x65, 0x74, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65,
|
||||
0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x49, 0x64, 0x22, 0x5c, 0x0a, 0x10, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65, 0x72, 0x55, 0x6e,
|
||||
0x62, 0x61, 0x6e, 0x6e, 0x65, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x5f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x61,
|
||||
0x63, 0x74, 0x6f, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61,
|
||||
0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64,
|
||||
0x22, 0xce, 0x09, 0x0a, 0x0c, 0x52, 0x6f, 0x6f, 0x6d, 0x47, 0x69, 0x66, 0x74, 0x53, 0x65, 0x6e,
|
||||
0x74, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65,
|
||||
0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65,
|
||||
0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74,
|
||||
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f,
|
||||
0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64,
|
||||
0x22, 0x82, 0x04, 0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x49,
|
||||
0x67, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65,
|
||||
0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72,
|
||||
0x72, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x25, 0x0a, 0x0e,
|
||||
0x66, 0x75, 0x65, 0x6c, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x75, 0x65, 0x6c, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68,
|
||||
0x6f, 0x6c, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61,
|
||||
0x74, 0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x69, 0x67, 0x6e, 0x69,
|
||||
0x74, 0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63,
|
||||
0x68, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c,
|
||||
0x61, 0x75, 0x6e, 0x63, 0x68, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x72, 0x6f,
|
||||
0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x53, 0x63, 0x6f,
|
||||
0x70, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65,
|
||||
0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76,
|
||||
0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x20,
|
||||
0x0a, 0x0c, 0x74, 0x6f, 0x70, 0x31, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x31, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64,
|
||||
0x12, 0x26, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x67, 0x6e, 0x69, 0x74,
|
||||
0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f,
|
||||
0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f,
|
||||
0x73, 0x68, 0x6f, 0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b,
|
||||
0x72, 0x6f, 0x6f, 0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x72,
|
||||
0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18,
|
||||
0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x76,
|
||||
0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x61,
|
||||
0x74, 0x5f, 0x6d, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65,
|
||||
0x74, 0x41, 0x74, 0x4d, 0x73, 0x22, 0xe6, 0x02, 0x0a, 0x12, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09,
|
||||
0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76,
|
||||
0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12,
|
||||
0x1d, 0x0a, 0x0a, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x24,
|
||||
0x0a, 0x0e, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x64,
|
||||
0x41, 0x74, 0x4d, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x74,
|
||||
0x5f, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65, 0x74,
|
||||
0x41, 0x74, 0x4d, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x70, 0x31, 0x5f, 0x75, 0x73, 0x65,
|
||||
0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x31,
|
||||
0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65,
|
||||
0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x0d, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x27,
|
||||
0x0a, 0x10, 0x69, 0x6e, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d,
|
||||
0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72,
|
||||
0x64, 0x73, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74,
|
||||
0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x76, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x56,
|
||||
0x61, 0x6c, 0x75, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x5f,
|
||||
0x72, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
|
||||
0x52, 0x10, 0x62, 0x69, 0x6c, 0x6c, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x63, 0x65, 0x69, 0x70, 0x74,
|
||||
0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65,
|
||||
0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76,
|
||||
0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x1d,
|
||||
0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x70, 0x6f, 0x6f, 0x6c, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x70, 0x6f, 0x6f, 0x6c, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x69, 0x6e, 0x5f, 0x73,
|
||||
0x70, 0x65, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x69, 0x6e,
|
||||
0x53, 0x70, 0x65, 0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x72, 0x79, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49,
|
||||
0x64, 0x12, 0x24, 0x0a, 0x0e, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x63,
|
||||
0x6f, 0x64, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x67, 0x69, 0x66, 0x74, 0x54,
|
||||
0x79, 0x70, 0x65, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x63, 0x70, 0x5f, 0x72, 0x65,
|
||||
0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x0e, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x0e, 0x63, 0x70, 0x52, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70,
|
||||
0x65, 0x12, 0x1b, 0x0a, 0x09, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0f,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x67, 0x69, 0x66, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22,
|
||||
0x0a, 0x0d, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18,
|
||||
0x10, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x67, 0x69, 0x66, 0x74, 0x49, 0x63, 0x6f, 0x6e, 0x55,
|
||||
0x72, 0x6c, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x61, 0x6e, 0x69, 0x6d, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x11, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10,
|
||||
0x67, 0x69, 0x66, 0x74, 0x41, 0x6e, 0x69, 0x6d, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x55, 0x72, 0x6c,
|
||||
0x12, 0x2a, 0x0a, 0x11, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x5f,
|
||||
0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x12, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x74, 0x61, 0x72,
|
||||
0x67, 0x65, 0x74, 0x47, 0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x2a, 0x0a, 0x11,
|
||||
0x67, 0x69, 0x66, 0x74, 0x5f, 0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x5f, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x18, 0x13, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x67, 0x69, 0x66, 0x74, 0x45, 0x66, 0x66,
|
||||
0x65, 0x63, 0x74, 0x54, 0x79, 0x70, 0x65, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x69, 0x73, 0x5f, 0x72,
|
||||
0x6f, 0x62, 0x6f, 0x74, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x18, 0x14, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x0b, 0x69, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x47, 0x69, 0x66, 0x74, 0x12, 0x30, 0x0a, 0x14,
|
||||
0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x5f, 0x6c, 0x75, 0x63, 0x6b, 0x79, 0x5f,
|
||||
0x67, 0x69, 0x66, 0x74, 0x18, 0x15, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x73, 0x79, 0x6e, 0x74,
|
||||
0x68, 0x65, 0x74, 0x69, 0x63, 0x4c, 0x75, 0x63, 0x6b, 0x79, 0x47, 0x69, 0x66, 0x74, 0x12, 0x2f,
|
||||
0x0a, 0x14, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x72, 0x6f, 0x62, 0x6f,
|
||||
0x74, 0x5f, 0x67, 0x69, 0x66, 0x74, 0x18, 0x16, 0x20, 0x01, 0x28, 0x08, 0x52, 0x11, 0x72, 0x65,
|
||||
0x61, 0x6c, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x47, 0x69, 0x66, 0x74, 0x12,
|
||||
0x1f, 0x0a, 0x0b, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x17,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65,
|
||||
0x12, 0x23, 0x0a, 0x0d, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61,
|
||||
0x72, 0x18, 0x18, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x41,
|
||||
0x76, 0x61, 0x74, 0x61, 0x72, 0x12, 0x33, 0x0a, 0x16, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f,
|
||||
0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
|
||||
0x19, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x44, 0x69, 0x73,
|
||||
0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x1d, 0x73, 0x65,
|
||||
0x6e, 0x64, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f, 0x64, 0x69, 0x73, 0x70,
|
||||
0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28,
|
||||
0x09, 0x52, 0x19, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x50, 0x72, 0x65, 0x74, 0x74, 0x79, 0x44,
|
||||
0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x2b, 0x0a, 0x11,
|
||||
0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x6e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d,
|
||||
0x65, 0x18, 0x1b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65,
|
||||
0x72, 0x4e, 0x69, 0x63, 0x6b, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x63,
|
||||
0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x61, 0x76, 0x61, 0x74, 0x61, 0x72, 0x18, 0x1c, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x41, 0x76, 0x61, 0x74,
|
||||
0x61, 0x72, 0x12, 0x37, 0x0a, 0x18, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x64,
|
||||
0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x1d,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x44, 0x69,
|
||||
0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x1f, 0x72,
|
||||
0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x5f, 0x70, 0x72, 0x65, 0x74, 0x74, 0x79, 0x5f, 0x64,
|
||||
0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x1e,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x1b, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x72, 0x50, 0x72,
|
||||
0x65, 0x74, 0x74, 0x79, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x55, 0x73, 0x65, 0x72, 0x49,
|
||||
0x64, 0x22, 0xf7, 0x04, 0x0a, 0x17, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x4c,
|
||||
0x75, 0x63, 0x6b, 0x79, 0x47, 0x69, 0x66, 0x74, 0x44, 0x72, 0x61, 0x77, 0x6e, 0x12, 0x17, 0x0a,
|
||||
0x07, 0x64, 0x72, 0x61, 0x77, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
|
||||
0x64, 0x72, 0x61, 0x77, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d,
|
||||
0x61, 0x6e, 0x64, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73,
|
||||
0x65, 0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e, 0x74,
|
||||
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x49,
|
||||
0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66, 0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69,
|
||||
0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09,
|
||||
0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x6f, 0x6f,
|
||||
0x6c, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6f, 0x6f, 0x6c,
|
||||
0x49, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x70, 0x6c, 0x69, 0x65, 0x72,
|
||||
0x5f, 0x70, 0x70, 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x6d, 0x75, 0x6c, 0x74,
|
||||
0x69, 0x70, 0x6c, 0x69, 0x65, 0x72, 0x50, 0x70, 0x6d, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x73,
|
||||
0x65, 0x5f, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x09,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x62, 0x61, 0x73, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64,
|
||||
0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x61, 0x74,
|
||||
0x6d, 0x6f, 0x73, 0x70, 0x68, 0x65, 0x72, 0x65, 0x5f, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f,
|
||||
0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x19, 0x72, 0x6f, 0x6f,
|
||||
0x6d, 0x41, 0x74, 0x6d, 0x6f, 0x73, 0x70, 0x68, 0x65, 0x72, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72,
|
||||
0x64, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x16, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69,
|
||||
0x74, 0x79, 0x5f, 0x73, 0x75, 0x62, 0x73, 0x69, 0x64, 0x79, 0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73,
|
||||
0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x61, 0x63, 0x74, 0x69, 0x76, 0x69, 0x74, 0x79,
|
||||
0x53, 0x75, 0x62, 0x73, 0x69, 0x64, 0x79, 0x43, 0x6f, 0x69, 0x6e, 0x73, 0x12, 0x34, 0x0a, 0x16,
|
||||
0x65, 0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64,
|
||||
0x5f, 0x63, 0x6f, 0x69, 0x6e, 0x73, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x14, 0x65, 0x66,
|
||||
0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x43, 0x6f, 0x69,
|
||||
0x6e, 0x73, 0x12, 0x22, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74,
|
||||
0x5f, 0x6d, 0x73, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x64, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c,
|
||||
0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x73, 0x5f, 0x72, 0x6f, 0x62, 0x6f, 0x74, 0x18, 0x0f,
|
||||
0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x69, 0x73, 0x52, 0x6f, 0x62, 0x6f, 0x74, 0x12, 0x1c, 0x0a,
|
||||
0x09, 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x18, 0x10, 0x20, 0x01, 0x28, 0x08,
|
||||
0x52, 0x09, 0x73, 0x79, 0x6e, 0x74, 0x68, 0x65, 0x74, 0x69, 0x63, 0x22, 0x4a, 0x0a, 0x0f, 0x52,
|
||||
0x6f, 0x6f, 0x6d, 0x48, 0x65, 0x61, 0x74, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x14,
|
||||
0x0a, 0x05, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x64,
|
||||
0x65, 0x6c, 0x74, 0x61, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f,
|
||||
0x68, 0x65, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x75, 0x72, 0x72,
|
||||
0x65, 0x6e, 0x74, 0x48, 0x65, 0x61, 0x74, 0x22, 0x5f, 0x0a, 0x0f, 0x52, 0x6f, 0x6f, 0x6d, 0x52,
|
||||
0x61, 0x6e, 0x6b, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65,
|
||||
0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x05, 0x73, 0x63, 0x6f, 0x72, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66,
|
||||
0x74, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x67,
|
||||
0x69, 0x66, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x94, 0x02, 0x0a, 0x15, 0x52, 0x6f, 0x6f,
|
||||
0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x47, 0x72, 0x61,
|
||||
0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x72, 0x6f, 0x6c,
|
||||
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x52,
|
||||
0x6f, 0x6c, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x24, 0x0a, 0x0e,
|
||||
0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x5f, 0x69, 0x74, 0x65, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x49, 0x74, 0x65, 0x6d,
|
||||
0x49, 0x64, 0x12, 0x2a, 0x0a, 0x11, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x67,
|
||||
0x72, 0x6f, 0x75, 0x70, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x72,
|
||||
0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x49, 0x64, 0x12, 0x21,
|
||||
0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x19, 0x0a, 0x08, 0x69, 0x63, 0x6f, 0x6e, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x07, 0x69, 0x63, 0x6f, 0x6e, 0x55, 0x72, 0x6c, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x67, 0x72, 0x61, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x67, 0x72, 0x61, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
|
||||
0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22,
|
||||
0xeb, 0x03, 0x0a, 0x15, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x46, 0x75,
|
||||
0x65, 0x6c, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x09, 0x61, 0x64, 0x64, 0x65, 0x64, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x30, 0x0a, 0x14, 0x65,
|
||||
0x66, 0x66, 0x65, 0x63, 0x74, 0x69, 0x76, 0x65, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x5f, 0x66,
|
||||
0x75, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x65, 0x66, 0x66, 0x65, 0x63,
|
||||
0x74, 0x69, 0x76, 0x65, 0x41, 0x64, 0x64, 0x65, 0x64, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x23, 0x0a,
|
||||
0x0d, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x05,
|
||||
0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x6f, 0x76, 0x65, 0x72, 0x66, 0x6c, 0x6f, 0x77, 0x46, 0x75,
|
||||
0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x66, 0x75,
|
||||
0x65, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
|
||||
0x74, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x75, 0x65, 0x6c, 0x5f, 0x74, 0x68,
|
||||
0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x66,
|
||||
0x75, 0x65, 0x6c, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x12, 0x16, 0x0a, 0x06,
|
||||
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74,
|
||||
0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x74,
|
||||
0x5f, 0x6d, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65, 0x74,
|
||||
0x41, 0x74, 0x4d, 0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x5f, 0x75,
|
||||
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65,
|
||||
0x6e, 0x64, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x67, 0x69,
|
||||
0x66, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x67, 0x69, 0x66,
|
||||
0x74, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x67, 0x69, 0x66, 0x74, 0x5f, 0x63, 0x6f, 0x75, 0x6e,
|
||||
0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x67, 0x69, 0x66, 0x74, 0x43, 0x6f, 0x75,
|
||||
0x6e, 0x74, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x49,
|
||||
0x64, 0x12, 0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67,
|
||||
0x69, 0x6f, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69,
|
||||
0x73, 0x69, 0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x22, 0x82, 0x04,
|
||||
0x0a, 0x11, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x67, 0x6e, 0x69,
|
||||
0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x64,
|
||||
0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52,
|
||||
0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e,
|
||||
0x74, 0x5f, 0x66, 0x75, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x63, 0x75,
|
||||
0x72, 0x72, 0x65, 0x6e, 0x74, 0x46, 0x75, 0x65, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x75, 0x65,
|
||||
0x6c, 0x5f, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0d, 0x66, 0x75, 0x65, 0x6c, 0x54, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64,
|
||||
0x12, 0x22, 0x0a, 0x0d, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d,
|
||||
0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x64,
|
||||
0x41, 0x74, 0x4d, 0x73, 0x12, 0x20, 0x0a, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x61,
|
||||
0x74, 0x5f, 0x6d, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x6c, 0x61, 0x75, 0x6e,
|
||||
0x63, 0x68, 0x41, 0x74, 0x4d, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63,
|
||||
0x61, 0x73, 0x74, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x0e, 0x62, 0x72, 0x6f, 0x61, 0x64, 0x63, 0x61, 0x73, 0x74, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12,
|
||||
0x2a, 0x0a, 0x11, 0x76, 0x69, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x5f, 0x72, 0x65, 0x67, 0x69, 0x6f,
|
||||
0x6e, 0x5f, 0x69, 0x64, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x76, 0x69, 0x73, 0x69,
|
||||
0x62, 0x6c, 0x65, 0x52, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x74,
|
||||
0x6f, 0x70, 0x31, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28,
|
||||
0x03, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x31, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x26, 0x0a,
|
||||
0x0f, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64,
|
||||
0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x72, 0x55,
|
||||
0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x49, 0x64, 0x12, 0x22, 0x0a, 0x0d, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x73, 0x68, 0x6f,
|
||||
0x72, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x72, 0x6f, 0x6f,
|
||||
0x6d, 0x53, 0x68, 0x6f, 0x72, 0x74, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x10, 0x72, 0x6f, 0x63, 0x6b,
|
||||
0x65, 0x74, 0x5f, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0d, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x0e, 0x72, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x43, 0x6f, 0x76, 0x65, 0x72, 0x55,
|
||||
0x72, 0x6c, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x74, 0x5f, 0x6d,
|
||||
0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65, 0x74, 0x41, 0x74,
|
||||
0x4d, 0x73, 0x22, 0xe6, 0x02, 0x0a, 0x12, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65,
|
||||
0x74, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x63,
|
||||
0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18,
|
||||
0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1d, 0x0a, 0x0a,
|
||||
0x6e, 0x65, 0x78, 0x74, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05,
|
||||
0x52, 0x09, 0x6e, 0x65, 0x78, 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x24, 0x0a, 0x0e, 0x6c,
|
||||
0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x04, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x0c, 0x6c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x64, 0x41, 0x74, 0x4d,
|
||||
0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x72, 0x65, 0x73, 0x65, 0x74, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73,
|
||||
0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x72, 0x65, 0x73, 0x65, 0x74, 0x41, 0x74, 0x4d,
|
||||
0x73, 0x12, 0x20, 0x0a, 0x0c, 0x74, 0x6f, 0x70, 0x31, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x70, 0x31, 0x55, 0x73, 0x65,
|
||||
0x72, 0x49, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x69, 0x67, 0x6e, 0x69, 0x74, 0x65, 0x72, 0x5f, 0x75,
|
||||
0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x67,
|
||||
0x6e, 0x69, 0x74, 0x65, 0x72, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x27, 0x0a, 0x10, 0x69,
|
||||
0x6e, 0x5f, 0x72, 0x6f, 0x6f, 0x6d, 0x5f, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x73, 0x18,
|
||||
0x08, 0x20, 0x03, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x52, 0x6f, 0x6f, 0x6d, 0x55, 0x73, 0x65,
|
||||
0x72, 0x49, 0x64, 0x73, 0x12, 0x45, 0x0a, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18,
|
||||
0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x65, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x73, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f,
|
||||
0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x47, 0x72, 0x61,
|
||||
0x6e, 0x74, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x17,
|
||||
0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x77, 0x61, 0x72, 0x64,
|
||||
0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x22, 0x93,
|
||||
0x01, 0x0a, 0x17, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x77,
|
||||
0x61, 0x72, 0x64, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f,
|
||||
0x63, 0x6b, 0x65, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72,
|
||||
0x6f, 0x63, 0x6b, 0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c,
|
||||
0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x45, 0x0a,
|
||||
0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x72, 0x6f,
|
||||
0x6f, 0x6d, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74,
|
||||
0x52, 0x65, 0x77, 0x61, 0x72, 0x64, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x07, 0x72, 0x65, 0x77,
|
||||
0x61, 0x72, 0x64, 0x73, 0x42, 0x33, 0x5a, 0x31, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f,
|
||||
0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x73, 0x2f, 0x72, 0x6f, 0x6f, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x6f,
|
||||
0x6d, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x33,
|
||||
0x47, 0x72, 0x61, 0x6e, 0x74, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x6f, 0x63, 0x6b, 0x65,
|
||||
0x74, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6f, 0x63, 0x6b,
|
||||
0x65, 0x74, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 0x20,
|
||||
0x01, 0x28, 0x05, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x45, 0x0a, 0x07, 0x72, 0x65,
|
||||
0x77, 0x61, 0x72, 0x64, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2b, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x72, 0x6f, 0x6f, 0x6d, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x52, 0x6f, 0x6f, 0x6d, 0x52, 0x6f, 0x63, 0x6b, 0x65, 0x74, 0x52, 0x65, 0x77,
|
||||
0x61, 0x72, 0x64, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x52, 0x07, 0x72, 0x65, 0x77, 0x61, 0x72, 0x64,
|
||||
0x73, 0x42, 0x33, 0x5a, 0x31, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c,
|
||||
0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x73, 0x2f, 0x72, 0x6f, 0x6f, 0x6d, 0x2f, 0x76, 0x31, 0x3b, 0x72, 0x6f, 0x6f, 0x6d, 0x65, 0x76,
|
||||
0x65, 0x6e, 0x74, 0x73, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
@ -65,6 +65,8 @@ message RoomUserJoined {
|
||||
RoomEntryVehicleSnapshot entry_vehicle = 4;
|
||||
int64 country_id = 5;
|
||||
int64 region_id = 6;
|
||||
// is_robot 标记本次进房来自房间机器人调度,统计服务必须跳过活跃用户口径。
|
||||
bool is_robot = 7;
|
||||
}
|
||||
|
||||
// RoomUserLeft 表达用户离房成功。
|
||||
@ -172,6 +174,16 @@ message RoomGiftSent {
|
||||
bool synthetic_lucky_gift = 21;
|
||||
// real_room_robot_gift 标记真人房机器人送出的真实热度礼物,用于 Databi 单独统计机器人投放价值。
|
||||
bool real_room_robot_gift = 22;
|
||||
// sender_name 是送礼入口固化的展示昵称,只用于客户端 IM 展示兜底,不作为用户主资料事实。
|
||||
string sender_name = 23;
|
||||
string sender_avatar = 24;
|
||||
string sender_display_user_id = 25;
|
||||
string sender_pretty_display_user_id = 26;
|
||||
// receiver_nickname 是收礼目标在送礼瞬间的展示昵称;字段名匹配 Flutter 已有解析逻辑。
|
||||
string receiver_nickname = 27;
|
||||
string receiver_avatar = 28;
|
||||
string receiver_display_user_id = 29;
|
||||
string receiver_pretty_display_user_id = 30;
|
||||
}
|
||||
|
||||
// RoomRobotLuckyGiftDrawn 是机器人房间专用幸运礼物展示事件。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -643,6 +643,8 @@ message JoinRoomRequest {
|
||||
RoomEntryVehicleSnapshot entry_vehicle = 4;
|
||||
int64 actor_country_id = 5;
|
||||
int64 actor_region_id = 6;
|
||||
// actor_is_robot 只由 room-service 内部机器人调度链路设置,外部 gateway 进房保持 false。
|
||||
bool actor_is_robot = 7;
|
||||
}
|
||||
|
||||
// JoinRoomResponse 返回加入后的房间快照。
|
||||
@ -1010,6 +1012,16 @@ message SendGiftTargetHostScope {
|
||||
int64 target_agency_owner_user_id = 4;
|
||||
}
|
||||
|
||||
// SendGiftDisplayProfile 是 gateway 在送礼入口固化的轻量展示快照。
|
||||
// room-service 只把它写入事件和 IM,不把用户资料扩散到 Room Cell 核心状态。
|
||||
message SendGiftDisplayProfile {
|
||||
int64 user_id = 1;
|
||||
string username = 2;
|
||||
string avatar = 3;
|
||||
string display_user_id = 4;
|
||||
string pretty_display_user_id = 5;
|
||||
}
|
||||
|
||||
// SendGiftRequest 是首版房间内最重要的变现命令。
|
||||
message SendGiftRequest {
|
||||
RequestMeta meta = 1;
|
||||
@ -1037,6 +1049,10 @@ message SendGiftRequest {
|
||||
string source = 14;
|
||||
// target_host_scopes 覆盖批量 target 的工资入账快照;单目标旧字段仍保留兼容老调用链。
|
||||
repeated SendGiftTargetHostScope target_host_scopes = 15;
|
||||
// sender_display_profile 是 gateway 从 user-service 读取的送礼人展示快照,用于 IM 兜底展示。
|
||||
SendGiftDisplayProfile sender_display_profile = 16;
|
||||
// target_display_profiles 是每个收礼目标的展示快照;多目标 IM 按 target_user_id 取对应项。
|
||||
repeated SendGiftDisplayProfile target_display_profiles = 17;
|
||||
}
|
||||
|
||||
// SendGiftResponse 返回扣费成功并落到房间后的状态结果。
|
||||
|
||||
@ -1142,6 +1142,274 @@ func (x *CheckLoginRiskIPWhitelistResponse) GetWhitelisted() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// RegisterRiskConfig 是注册链路读取的风控配置。
|
||||
type RegisterRiskConfig struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
AppCode string `protobuf:"bytes,1,opt,name=app_code,json=appCode,proto3" json:"app_code,omitempty"`
|
||||
MaxAccountsPerDevice int32 `protobuf:"varint,2,opt,name=max_accounts_per_device,json=maxAccountsPerDevice,proto3" json:"max_accounts_per_device,omitempty"`
|
||||
UpdatedAtMs int64 `protobuf:"varint,3,opt,name=updated_at_ms,json=updatedAtMs,proto3" json:"updated_at_ms,omitempty"`
|
||||
UpdatedByAdminId int64 `protobuf:"varint,4,opt,name=updated_by_admin_id,json=updatedByAdminId,proto3" json:"updated_by_admin_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RegisterRiskConfig) Reset() {
|
||||
*x = RegisterRiskConfig{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[15]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RegisterRiskConfig) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RegisterRiskConfig) ProtoMessage() {}
|
||||
|
||||
func (x *RegisterRiskConfig) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[15]
|
||||
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 RegisterRiskConfig.ProtoReflect.Descriptor instead.
|
||||
func (*RegisterRiskConfig) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{15}
|
||||
}
|
||||
|
||||
func (x *RegisterRiskConfig) GetAppCode() string {
|
||||
if x != nil {
|
||||
return x.AppCode
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RegisterRiskConfig) GetMaxAccountsPerDevice() int32 {
|
||||
if x != nil {
|
||||
return x.MaxAccountsPerDevice
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RegisterRiskConfig) GetUpdatedAtMs() int64 {
|
||||
if x != nil {
|
||||
return x.UpdatedAtMs
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *RegisterRiskConfig) GetUpdatedByAdminId() int64 {
|
||||
if x != nil {
|
||||
return x.UpdatedByAdminId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// GetRegisterRiskConfigRequest 查询当前 App 的注册风控配置。
|
||||
type GetRegisterRiskConfigRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetRegisterRiskConfigRequest) Reset() {
|
||||
*x = GetRegisterRiskConfigRequest{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[16]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetRegisterRiskConfigRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetRegisterRiskConfigRequest) ProtoMessage() {}
|
||||
|
||||
func (x *GetRegisterRiskConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[16]
|
||||
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 GetRegisterRiskConfigRequest.ProtoReflect.Descriptor instead.
|
||||
func (*GetRegisterRiskConfigRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{16}
|
||||
}
|
||||
|
||||
func (x *GetRegisterRiskConfigRequest) GetMeta() *RequestMeta {
|
||||
if x != nil {
|
||||
return x.Meta
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type GetRegisterRiskConfigResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Config *RegisterRiskConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetRegisterRiskConfigResponse) Reset() {
|
||||
*x = GetRegisterRiskConfigResponse{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[17]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *GetRegisterRiskConfigResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetRegisterRiskConfigResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetRegisterRiskConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[17]
|
||||
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 GetRegisterRiskConfigResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetRegisterRiskConfigResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{17}
|
||||
}
|
||||
|
||||
func (x *GetRegisterRiskConfigResponse) GetConfig() *RegisterRiskConfig {
|
||||
if x != nil {
|
||||
return x.Config
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateRegisterRiskConfigRequest 由后台保存当前 App 的注册风控配置。
|
||||
type UpdateRegisterRiskConfigRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Meta *RequestMeta `protobuf:"bytes,1,opt,name=meta,proto3" json:"meta,omitempty"`
|
||||
MaxAccountsPerDevice int32 `protobuf:"varint,2,opt,name=max_accounts_per_device,json=maxAccountsPerDevice,proto3" json:"max_accounts_per_device,omitempty"`
|
||||
OperatorAdminId int64 `protobuf:"varint,3,opt,name=operator_admin_id,json=operatorAdminId,proto3" json:"operator_admin_id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigRequest) Reset() {
|
||||
*x = UpdateRegisterRiskConfigRequest{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[18]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateRegisterRiskConfigRequest) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[18]
|
||||
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 UpdateRegisterRiskConfigRequest.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateRegisterRiskConfigRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{18}
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigRequest) GetMeta() *RequestMeta {
|
||||
if x != nil {
|
||||
return x.Meta
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigRequest) GetMaxAccountsPerDevice() int32 {
|
||||
if x != nil {
|
||||
return x.MaxAccountsPerDevice
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigRequest) GetOperatorAdminId() int64 {
|
||||
if x != nil {
|
||||
return x.OperatorAdminId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type UpdateRegisterRiskConfigResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Config *RegisterRiskConfig `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"`
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigResponse) Reset() {
|
||||
*x = UpdateRegisterRiskConfigResponse{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[19]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*UpdateRegisterRiskConfigResponse) ProtoMessage() {}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[19]
|
||||
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 UpdateRegisterRiskConfigResponse.ProtoReflect.Descriptor instead.
|
||||
func (*UpdateRegisterRiskConfigResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{19}
|
||||
}
|
||||
|
||||
func (x *UpdateRegisterRiskConfigResponse) GetConfig() *RegisterRiskConfig {
|
||||
if x != nil {
|
||||
return x.Config
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AppHeartbeatRequest 刷新当前登录会话的 App 在线心跳。
|
||||
type AppHeartbeatRequest struct {
|
||||
state protoimpl.MessageState
|
||||
@ -1155,7 +1423,7 @@ type AppHeartbeatRequest struct {
|
||||
|
||||
func (x *AppHeartbeatRequest) Reset() {
|
||||
*x = AppHeartbeatRequest{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[15]
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[20]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1167,7 +1435,7 @@ func (x *AppHeartbeatRequest) String() string {
|
||||
func (*AppHeartbeatRequest) ProtoMessage() {}
|
||||
|
||||
func (x *AppHeartbeatRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[15]
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[20]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1180,7 +1448,7 @@ func (x *AppHeartbeatRequest) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AppHeartbeatRequest.ProtoReflect.Descriptor instead.
|
||||
func (*AppHeartbeatRequest) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{15}
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{20}
|
||||
}
|
||||
|
||||
func (x *AppHeartbeatRequest) GetMeta() *RequestMeta {
|
||||
@ -1218,7 +1486,7 @@ type AppHeartbeatResponse struct {
|
||||
|
||||
func (x *AppHeartbeatResponse) Reset() {
|
||||
*x = AppHeartbeatResponse{}
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[16]
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[21]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
@ -1230,7 +1498,7 @@ func (x *AppHeartbeatResponse) String() string {
|
||||
func (*AppHeartbeatResponse) ProtoMessage() {}
|
||||
|
||||
func (x *AppHeartbeatResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[16]
|
||||
mi := &file_proto_user_v1_auth_proto_msgTypes[21]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
@ -1243,7 +1511,7 @@ func (x *AppHeartbeatResponse) ProtoReflect() protoreflect.Message {
|
||||
|
||||
// Deprecated: Use AppHeartbeatResponse.ProtoReflect.Descriptor instead.
|
||||
func (*AppHeartbeatResponse) Descriptor() ([]byte, []int) {
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{16}
|
||||
return file_proto_user_v1_auth_proto_rawDescGZIP(), []int{21}
|
||||
}
|
||||
|
||||
func (x *AppHeartbeatResponse) GetAccepted() bool {
|
||||
@ -1447,83 +1715,138 @@ var file_proto_user_v1_auth_proto_rawDesc = []byte{
|
||||
0x49, 0x50, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f,
|
||||
0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74,
|
||||
0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x68, 0x69, 0x74, 0x65, 0x6c,
|
||||
0x69, 0x73, 0x74, 0x65, 0x64, 0x22, 0x7d, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72,
|
||||
0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04,
|
||||
0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07,
|
||||
0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75,
|
||||
0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69,
|
||||
0x6f, 0x6e, 0x49, 0x64, 0x22, 0xb0, 0x01, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72,
|
||||
0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a,
|
||||
0x08, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52,
|
||||
0x08, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x65, 0x61,
|
||||
0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x03, 0x52, 0x0d, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x41, 0x74, 0x4d,
|
||||
0x73, 0x12, 0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65,
|
||||
0x5f, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65,
|
||||
0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xdc, 0x06, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68,
|
||||
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e,
|
||||
0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61,
|
||||
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75,
|
||||
0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x0f, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x12, 0x25, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
|
||||
0x65, 0x12, 0x54, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64,
|
||||
0x12, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52,
|
||||
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x51, 0x75, 0x69, 0x63, 0x6b,
|
||||
0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75,
|
||||
0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65,
|
||||
0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b,
|
||||
0x65, 0x6e, 0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f,
|
||||
0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x4c,
|
||||
0x6f, 0x67, 0x6f, 0x75, 0x74, 0x12, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75,
|
||||
0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a,
|
||||
0x19, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x69, 0x73, 0x6b, 0x49,
|
||||
0x50, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x2f, 0x2e, 0x68, 0x79, 0x61,
|
||||
0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b,
|
||||
0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x69, 0x73, 0x6b, 0x49, 0x50, 0x57, 0x68, 0x69, 0x74, 0x65,
|
||||
0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63,
|
||||
0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x69, 0x73, 0x6b, 0x49, 0x50, 0x57, 0x68, 0x69, 0x74,
|
||||
0x65, 0x6c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a,
|
||||
0x0c, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x22, 0x2e,
|
||||
0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70,
|
||||
0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65,
|
||||
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e,
|
||||
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
|
||||
0x75, 0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
0x69, 0x73, 0x74, 0x65, 0x64, 0x22, 0xb9, 0x01, 0x0a, 0x12, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
|
||||
0x65, 0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08,
|
||||
0x61, 0x70, 0x70, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07,
|
||||
0x61, 0x70, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x61,
|
||||
0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x76, 0x69,
|
||||
0x63, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x14, 0x6d, 0x61, 0x78, 0x41, 0x63, 0x63,
|
||||
0x6f, 0x75, 0x6e, 0x74, 0x73, 0x50, 0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x22,
|
||||
0x0a, 0x0d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18,
|
||||
0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74,
|
||||
0x4d, 0x73, 0x12, 0x2d, 0x0a, 0x13, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x62, 0x79,
|
||||
0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52,
|
||||
0x10, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x42, 0x79, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x49,
|
||||
0x64, 0x22, 0x4e, 0x0a, 0x1c, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
|
||||
0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74,
|
||||
0x61, 0x22, 0x5a, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
|
||||
0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
|
||||
0x73, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01,
|
||||
0x28, 0x0b, 0x32, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x69, 0x73, 0x6b, 0x43,
|
||||
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0xb4, 0x01,
|
||||
0x0a, 0x1f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
|
||||
0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
|
||||
0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74,
|
||||
0x61, 0x12, 0x35, 0x0a, 0x17, 0x6d, 0x61, 0x78, 0x5f, 0x61, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74,
|
||||
0x73, 0x5f, 0x70, 0x65, 0x72, 0x5f, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x18, 0x02, 0x20, 0x01,
|
||||
0x28, 0x05, 0x52, 0x14, 0x6d, 0x61, 0x78, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x50,
|
||||
0x65, 0x72, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x6f, 0x70, 0x65, 0x72,
|
||||
0x61, 0x74, 0x6f, 0x72, 0x5f, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20,
|
||||
0x01, 0x28, 0x03, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x41, 0x64, 0x6d,
|
||||
0x69, 0x6e, 0x49, 0x64, 0x22, 0x5d, 0x0a, 0x20, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65,
|
||||
0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x39, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
|
||||
0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x22, 0x7d, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62,
|
||||
0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2e, 0x0a, 0x04, 0x6d, 0x65,
|
||||
0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x4d, 0x65, 0x74, 0x61, 0x52, 0x04, 0x6d, 0x65, 0x74, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73,
|
||||
0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x06, 0x75, 0x73, 0x65,
|
||||
0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x69,
|
||||
0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e,
|
||||
0x49, 0x64, 0x22, 0xb0, 0x01, 0x0a, 0x14, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62,
|
||||
0x65, 0x61, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x61,
|
||||
0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x61,
|
||||
0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0f, 0x68, 0x65, 0x61, 0x72, 0x74,
|
||||
0x62, 0x65, 0x61, 0x74, 0x5f, 0x61, 0x74, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
|
||||
0x52, 0x0d, 0x68, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x41, 0x74, 0x4d, 0x73, 0x12,
|
||||
0x24, 0x0a, 0x0e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d,
|
||||
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x54,
|
||||
0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x2e, 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x04,
|
||||
0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x05,
|
||||
0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xcd, 0x08, 0x0a, 0x0b, 0x41, 0x75, 0x74, 0x68, 0x53, 0x65,
|
||||
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x51, 0x0a, 0x0d, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61,
|
||||
0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x50, 0x61, 0x73, 0x73,
|
||||
0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x55, 0x0a, 0x0f, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x12, 0x25, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x69,
|
||||
0x6e, 0x54, 0x68, 0x69, 0x72, 0x64, 0x50, 0x61, 0x72, 0x74, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65,
|
||||
0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x41, 0x75, 0x74, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x54, 0x0a, 0x0b, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x21,
|
||||
0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x53,
|
||||
0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x53, 0x65, 0x74, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x69, 0x0a, 0x12, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72,
|
||||
0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x69, 0x63,
|
||||
0x6b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65,
|
||||
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73,
|
||||
0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x51, 0x75, 0x69, 0x63, 0x6b, 0x43, 0x72, 0x65, 0x61, 0x74,
|
||||
0x65, 0x41, 0x63, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x57, 0x0a, 0x0c, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
|
||||
0x12, 0x22, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x54, 0x6f, 0x6b, 0x65,
|
||||
0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x45, 0x0a, 0x06, 0x4c, 0x6f, 0x67,
|
||||
0x6f, 0x75, 0x74, 0x12, 0x1c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1d, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x12, 0x69, 0x0a, 0x12, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x42,
|
||||
0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x12, 0x28, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67,
|
||||
0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x29, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x63, 0x6f, 0x72, 0x64, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x42, 0x6c, 0x6f, 0x63,
|
||||
0x6b, 0x65, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7e, 0x0a, 0x19, 0x43,
|
||||
0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x69, 0x73, 0x6b, 0x49, 0x50, 0x57,
|
||||
0x68, 0x69, 0x74, 0x65, 0x6c, 0x69, 0x73, 0x74, 0x12, 0x2f, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70,
|
||||
0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c, 0x6f,
|
||||
0x67, 0x69, 0x6e, 0x52, 0x69, 0x73, 0x6b, 0x49, 0x50, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c, 0x69,
|
||||
0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x68, 0x79, 0x61, 0x70,
|
||||
0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x4c,
|
||||
0x6f, 0x67, 0x69, 0x6e, 0x52, 0x69, 0x73, 0x6b, 0x49, 0x50, 0x57, 0x68, 0x69, 0x74, 0x65, 0x6c,
|
||||
0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x72, 0x0a, 0x15, 0x47,
|
||||
0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x12, 0x2b, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65,
|
||||
0x72, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72,
|
||||
0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x2c, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x47, 0x65, 0x74, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x69, 0x73,
|
||||
0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x7b, 0x0a, 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
|
||||
0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x2e, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x68, 0x79,
|
||||
0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61,
|
||||
0x74, 0x65, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x69, 0x73, 0x6b, 0x43, 0x6f,
|
||||
0x6e, 0x66, 0x69, 0x67, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x57, 0x0a, 0x0c,
|
||||
0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x12, 0x22, 0x2e, 0x68,
|
||||
0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31, 0x2e, 0x41, 0x70, 0x70,
|
||||
0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x23, 0x2e, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x75, 0x73, 0x65, 0x72, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x41, 0x70, 0x70, 0x48, 0x65, 0x61, 0x72, 0x74, 0x62, 0x65, 0x61, 0x74, 0x52, 0x65, 0x73,
|
||||
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x26, 0x5a, 0x24, 0x68, 0x79, 0x61, 0x70, 0x70, 0x2e, 0x6c,
|
||||
0x6f, 0x63, 0x61, 0x6c, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x75,
|
||||
0x73, 0x65, 0x72, 0x2f, 0x76, 0x31, 0x3b, 0x75, 0x73, 0x65, 0x72, 0x76, 0x31, 0x62, 0x06, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@ -1538,7 +1861,7 @@ func file_proto_user_v1_auth_proto_rawDescGZIP() []byte {
|
||||
return file_proto_user_v1_auth_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_proto_user_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 17)
|
||||
var file_proto_user_v1_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 22)
|
||||
var file_proto_user_v1_auth_proto_goTypes = []any{
|
||||
(*LoginPasswordRequest)(nil), // 0: hyapp.user.v1.LoginPasswordRequest
|
||||
(*LoginThirdPartyRequest)(nil), // 1: hyapp.user.v1.LoginThirdPartyRequest
|
||||
@ -1555,48 +1878,61 @@ var file_proto_user_v1_auth_proto_goTypes = []any{
|
||||
(*RecordLoginBlockedResponse)(nil), // 12: hyapp.user.v1.RecordLoginBlockedResponse
|
||||
(*CheckLoginRiskIPWhitelistRequest)(nil), // 13: hyapp.user.v1.CheckLoginRiskIPWhitelistRequest
|
||||
(*CheckLoginRiskIPWhitelistResponse)(nil), // 14: hyapp.user.v1.CheckLoginRiskIPWhitelistResponse
|
||||
(*AppHeartbeatRequest)(nil), // 15: hyapp.user.v1.AppHeartbeatRequest
|
||||
(*AppHeartbeatResponse)(nil), // 16: hyapp.user.v1.AppHeartbeatResponse
|
||||
(*RequestMeta)(nil), // 17: hyapp.user.v1.RequestMeta
|
||||
(*AuthToken)(nil), // 18: hyapp.user.v1.AuthToken
|
||||
(*RegisterRiskConfig)(nil), // 15: hyapp.user.v1.RegisterRiskConfig
|
||||
(*GetRegisterRiskConfigRequest)(nil), // 16: hyapp.user.v1.GetRegisterRiskConfigRequest
|
||||
(*GetRegisterRiskConfigResponse)(nil), // 17: hyapp.user.v1.GetRegisterRiskConfigResponse
|
||||
(*UpdateRegisterRiskConfigRequest)(nil), // 18: hyapp.user.v1.UpdateRegisterRiskConfigRequest
|
||||
(*UpdateRegisterRiskConfigResponse)(nil), // 19: hyapp.user.v1.UpdateRegisterRiskConfigResponse
|
||||
(*AppHeartbeatRequest)(nil), // 20: hyapp.user.v1.AppHeartbeatRequest
|
||||
(*AppHeartbeatResponse)(nil), // 21: hyapp.user.v1.AppHeartbeatResponse
|
||||
(*RequestMeta)(nil), // 22: hyapp.user.v1.RequestMeta
|
||||
(*AuthToken)(nil), // 23: hyapp.user.v1.AuthToken
|
||||
}
|
||||
var file_proto_user_v1_auth_proto_depIdxs = []int32{
|
||||
17, // 0: hyapp.user.v1.LoginPasswordRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
17, // 1: hyapp.user.v1.LoginThirdPartyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
18, // 2: hyapp.user.v1.AuthResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
17, // 3: hyapp.user.v1.SetPasswordRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
17, // 4: hyapp.user.v1.QuickCreateAccountRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
18, // 5: hyapp.user.v1.QuickCreateAccountResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
17, // 6: hyapp.user.v1.RefreshTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
18, // 7: hyapp.user.v1.RefreshTokenResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
17, // 8: hyapp.user.v1.LogoutRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
17, // 9: hyapp.user.v1.RecordLoginBlockedRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
17, // 10: hyapp.user.v1.CheckLoginRiskIPWhitelistRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
17, // 11: hyapp.user.v1.AppHeartbeatRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
18, // 12: hyapp.user.v1.AppHeartbeatResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
0, // 13: hyapp.user.v1.AuthService.LoginPassword:input_type -> hyapp.user.v1.LoginPasswordRequest
|
||||
1, // 14: hyapp.user.v1.AuthService.LoginThirdParty:input_type -> hyapp.user.v1.LoginThirdPartyRequest
|
||||
3, // 15: hyapp.user.v1.AuthService.SetPassword:input_type -> hyapp.user.v1.SetPasswordRequest
|
||||
5, // 16: hyapp.user.v1.AuthService.QuickCreateAccount:input_type -> hyapp.user.v1.QuickCreateAccountRequest
|
||||
7, // 17: hyapp.user.v1.AuthService.RefreshToken:input_type -> hyapp.user.v1.RefreshTokenRequest
|
||||
9, // 18: hyapp.user.v1.AuthService.Logout:input_type -> hyapp.user.v1.LogoutRequest
|
||||
11, // 19: hyapp.user.v1.AuthService.RecordLoginBlocked:input_type -> hyapp.user.v1.RecordLoginBlockedRequest
|
||||
13, // 20: hyapp.user.v1.AuthService.CheckLoginRiskIPWhitelist:input_type -> hyapp.user.v1.CheckLoginRiskIPWhitelistRequest
|
||||
15, // 21: hyapp.user.v1.AuthService.AppHeartbeat:input_type -> hyapp.user.v1.AppHeartbeatRequest
|
||||
2, // 22: hyapp.user.v1.AuthService.LoginPassword:output_type -> hyapp.user.v1.AuthResponse
|
||||
2, // 23: hyapp.user.v1.AuthService.LoginThirdParty:output_type -> hyapp.user.v1.AuthResponse
|
||||
4, // 24: hyapp.user.v1.AuthService.SetPassword:output_type -> hyapp.user.v1.SetPasswordResponse
|
||||
6, // 25: hyapp.user.v1.AuthService.QuickCreateAccount:output_type -> hyapp.user.v1.QuickCreateAccountResponse
|
||||
8, // 26: hyapp.user.v1.AuthService.RefreshToken:output_type -> hyapp.user.v1.RefreshTokenResponse
|
||||
10, // 27: hyapp.user.v1.AuthService.Logout:output_type -> hyapp.user.v1.LogoutResponse
|
||||
12, // 28: hyapp.user.v1.AuthService.RecordLoginBlocked:output_type -> hyapp.user.v1.RecordLoginBlockedResponse
|
||||
14, // 29: hyapp.user.v1.AuthService.CheckLoginRiskIPWhitelist:output_type -> hyapp.user.v1.CheckLoginRiskIPWhitelistResponse
|
||||
16, // 30: hyapp.user.v1.AuthService.AppHeartbeat:output_type -> hyapp.user.v1.AppHeartbeatResponse
|
||||
22, // [22:31] is the sub-list for method output_type
|
||||
13, // [13:22] is the sub-list for method input_type
|
||||
13, // [13:13] is the sub-list for extension type_name
|
||||
13, // [13:13] is the sub-list for extension extendee
|
||||
0, // [0:13] is the sub-list for field type_name
|
||||
22, // 0: hyapp.user.v1.LoginPasswordRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
22, // 1: hyapp.user.v1.LoginThirdPartyRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
23, // 2: hyapp.user.v1.AuthResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
22, // 3: hyapp.user.v1.SetPasswordRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
22, // 4: hyapp.user.v1.QuickCreateAccountRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
23, // 5: hyapp.user.v1.QuickCreateAccountResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
22, // 6: hyapp.user.v1.RefreshTokenRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
23, // 7: hyapp.user.v1.RefreshTokenResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
22, // 8: hyapp.user.v1.LogoutRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
22, // 9: hyapp.user.v1.RecordLoginBlockedRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
22, // 10: hyapp.user.v1.CheckLoginRiskIPWhitelistRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
22, // 11: hyapp.user.v1.GetRegisterRiskConfigRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
15, // 12: hyapp.user.v1.GetRegisterRiskConfigResponse.config:type_name -> hyapp.user.v1.RegisterRiskConfig
|
||||
22, // 13: hyapp.user.v1.UpdateRegisterRiskConfigRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
15, // 14: hyapp.user.v1.UpdateRegisterRiskConfigResponse.config:type_name -> hyapp.user.v1.RegisterRiskConfig
|
||||
22, // 15: hyapp.user.v1.AppHeartbeatRequest.meta:type_name -> hyapp.user.v1.RequestMeta
|
||||
23, // 16: hyapp.user.v1.AppHeartbeatResponse.token:type_name -> hyapp.user.v1.AuthToken
|
||||
0, // 17: hyapp.user.v1.AuthService.LoginPassword:input_type -> hyapp.user.v1.LoginPasswordRequest
|
||||
1, // 18: hyapp.user.v1.AuthService.LoginThirdParty:input_type -> hyapp.user.v1.LoginThirdPartyRequest
|
||||
3, // 19: hyapp.user.v1.AuthService.SetPassword:input_type -> hyapp.user.v1.SetPasswordRequest
|
||||
5, // 20: hyapp.user.v1.AuthService.QuickCreateAccount:input_type -> hyapp.user.v1.QuickCreateAccountRequest
|
||||
7, // 21: hyapp.user.v1.AuthService.RefreshToken:input_type -> hyapp.user.v1.RefreshTokenRequest
|
||||
9, // 22: hyapp.user.v1.AuthService.Logout:input_type -> hyapp.user.v1.LogoutRequest
|
||||
11, // 23: hyapp.user.v1.AuthService.RecordLoginBlocked:input_type -> hyapp.user.v1.RecordLoginBlockedRequest
|
||||
13, // 24: hyapp.user.v1.AuthService.CheckLoginRiskIPWhitelist:input_type -> hyapp.user.v1.CheckLoginRiskIPWhitelistRequest
|
||||
16, // 25: hyapp.user.v1.AuthService.GetRegisterRiskConfig:input_type -> hyapp.user.v1.GetRegisterRiskConfigRequest
|
||||
18, // 26: hyapp.user.v1.AuthService.UpdateRegisterRiskConfig:input_type -> hyapp.user.v1.UpdateRegisterRiskConfigRequest
|
||||
20, // 27: hyapp.user.v1.AuthService.AppHeartbeat:input_type -> hyapp.user.v1.AppHeartbeatRequest
|
||||
2, // 28: hyapp.user.v1.AuthService.LoginPassword:output_type -> hyapp.user.v1.AuthResponse
|
||||
2, // 29: hyapp.user.v1.AuthService.LoginThirdParty:output_type -> hyapp.user.v1.AuthResponse
|
||||
4, // 30: hyapp.user.v1.AuthService.SetPassword:output_type -> hyapp.user.v1.SetPasswordResponse
|
||||
6, // 31: hyapp.user.v1.AuthService.QuickCreateAccount:output_type -> hyapp.user.v1.QuickCreateAccountResponse
|
||||
8, // 32: hyapp.user.v1.AuthService.RefreshToken:output_type -> hyapp.user.v1.RefreshTokenResponse
|
||||
10, // 33: hyapp.user.v1.AuthService.Logout:output_type -> hyapp.user.v1.LogoutResponse
|
||||
12, // 34: hyapp.user.v1.AuthService.RecordLoginBlocked:output_type -> hyapp.user.v1.RecordLoginBlockedResponse
|
||||
14, // 35: hyapp.user.v1.AuthService.CheckLoginRiskIPWhitelist:output_type -> hyapp.user.v1.CheckLoginRiskIPWhitelistResponse
|
||||
17, // 36: hyapp.user.v1.AuthService.GetRegisterRiskConfig:output_type -> hyapp.user.v1.GetRegisterRiskConfigResponse
|
||||
19, // 37: hyapp.user.v1.AuthService.UpdateRegisterRiskConfig:output_type -> hyapp.user.v1.UpdateRegisterRiskConfigResponse
|
||||
21, // 38: hyapp.user.v1.AuthService.AppHeartbeat:output_type -> hyapp.user.v1.AppHeartbeatResponse
|
||||
28, // [28:39] is the sub-list for method output_type
|
||||
17, // [17:28] is the sub-list for method input_type
|
||||
17, // [17:17] is the sub-list for extension type_name
|
||||
17, // [17:17] is the sub-list for extension extendee
|
||||
0, // [0:17] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_proto_user_v1_auth_proto_init() }
|
||||
@ -1611,7 +1947,7 @@ func file_proto_user_v1_auth_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_proto_user_v1_auth_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 17,
|
||||
NumMessages: 22,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@ -135,6 +135,34 @@ message CheckLoginRiskIPWhitelistResponse {
|
||||
bool whitelisted = 1;
|
||||
}
|
||||
|
||||
// RegisterRiskConfig 是注册链路读取的风控配置。
|
||||
message RegisterRiskConfig {
|
||||
string app_code = 1;
|
||||
int32 max_accounts_per_device = 2;
|
||||
int64 updated_at_ms = 3;
|
||||
int64 updated_by_admin_id = 4;
|
||||
}
|
||||
|
||||
// GetRegisterRiskConfigRequest 查询当前 App 的注册风控配置。
|
||||
message GetRegisterRiskConfigRequest {
|
||||
RequestMeta meta = 1;
|
||||
}
|
||||
|
||||
message GetRegisterRiskConfigResponse {
|
||||
RegisterRiskConfig config = 1;
|
||||
}
|
||||
|
||||
// UpdateRegisterRiskConfigRequest 由后台保存当前 App 的注册风控配置。
|
||||
message UpdateRegisterRiskConfigRequest {
|
||||
RequestMeta meta = 1;
|
||||
int32 max_accounts_per_device = 2;
|
||||
int64 operator_admin_id = 3;
|
||||
}
|
||||
|
||||
message UpdateRegisterRiskConfigResponse {
|
||||
RegisterRiskConfig config = 1;
|
||||
}
|
||||
|
||||
// AppHeartbeatRequest 刷新当前登录会话的 App 在线心跳。
|
||||
message AppHeartbeatRequest {
|
||||
RequestMeta meta = 1;
|
||||
@ -160,5 +188,7 @@ service AuthService {
|
||||
rpc Logout(LogoutRequest) returns (LogoutResponse);
|
||||
rpc RecordLoginBlocked(RecordLoginBlockedRequest) returns (RecordLoginBlockedResponse);
|
||||
rpc CheckLoginRiskIPWhitelist(CheckLoginRiskIPWhitelistRequest) returns (CheckLoginRiskIPWhitelistResponse);
|
||||
rpc GetRegisterRiskConfig(GetRegisterRiskConfigRequest) returns (GetRegisterRiskConfigResponse);
|
||||
rpc UpdateRegisterRiskConfig(UpdateRegisterRiskConfigRequest) returns (UpdateRegisterRiskConfigResponse);
|
||||
rpc AppHeartbeat(AppHeartbeatRequest) returns (AppHeartbeatResponse);
|
||||
}
|
||||
|
||||
@ -27,6 +27,8 @@ const (
|
||||
AuthService_Logout_FullMethodName = "/hyapp.user.v1.AuthService/Logout"
|
||||
AuthService_RecordLoginBlocked_FullMethodName = "/hyapp.user.v1.AuthService/RecordLoginBlocked"
|
||||
AuthService_CheckLoginRiskIPWhitelist_FullMethodName = "/hyapp.user.v1.AuthService/CheckLoginRiskIPWhitelist"
|
||||
AuthService_GetRegisterRiskConfig_FullMethodName = "/hyapp.user.v1.AuthService/GetRegisterRiskConfig"
|
||||
AuthService_UpdateRegisterRiskConfig_FullMethodName = "/hyapp.user.v1.AuthService/UpdateRegisterRiskConfig"
|
||||
AuthService_AppHeartbeat_FullMethodName = "/hyapp.user.v1.AuthService/AppHeartbeat"
|
||||
)
|
||||
|
||||
@ -44,6 +46,8 @@ type AuthServiceClient interface {
|
||||
Logout(ctx context.Context, in *LogoutRequest, opts ...grpc.CallOption) (*LogoutResponse, error)
|
||||
RecordLoginBlocked(ctx context.Context, in *RecordLoginBlockedRequest, opts ...grpc.CallOption) (*RecordLoginBlockedResponse, error)
|
||||
CheckLoginRiskIPWhitelist(ctx context.Context, in *CheckLoginRiskIPWhitelistRequest, opts ...grpc.CallOption) (*CheckLoginRiskIPWhitelistResponse, error)
|
||||
GetRegisterRiskConfig(ctx context.Context, in *GetRegisterRiskConfigRequest, opts ...grpc.CallOption) (*GetRegisterRiskConfigResponse, error)
|
||||
UpdateRegisterRiskConfig(ctx context.Context, in *UpdateRegisterRiskConfigRequest, opts ...grpc.CallOption) (*UpdateRegisterRiskConfigResponse, error)
|
||||
AppHeartbeat(ctx context.Context, in *AppHeartbeatRequest, opts ...grpc.CallOption) (*AppHeartbeatResponse, error)
|
||||
}
|
||||
|
||||
@ -135,6 +139,26 @@ func (c *authServiceClient) CheckLoginRiskIPWhitelist(ctx context.Context, in *C
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) GetRegisterRiskConfig(ctx context.Context, in *GetRegisterRiskConfigRequest, opts ...grpc.CallOption) (*GetRegisterRiskConfigResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(GetRegisterRiskConfigResponse)
|
||||
err := c.cc.Invoke(ctx, AuthService_GetRegisterRiskConfig_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) UpdateRegisterRiskConfig(ctx context.Context, in *UpdateRegisterRiskConfigRequest, opts ...grpc.CallOption) (*UpdateRegisterRiskConfigResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(UpdateRegisterRiskConfigResponse)
|
||||
err := c.cc.Invoke(ctx, AuthService_UpdateRegisterRiskConfig_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *authServiceClient) AppHeartbeat(ctx context.Context, in *AppHeartbeatRequest, opts ...grpc.CallOption) (*AppHeartbeatResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(AppHeartbeatResponse)
|
||||
@ -159,6 +183,8 @@ type AuthServiceServer interface {
|
||||
Logout(context.Context, *LogoutRequest) (*LogoutResponse, error)
|
||||
RecordLoginBlocked(context.Context, *RecordLoginBlockedRequest) (*RecordLoginBlockedResponse, error)
|
||||
CheckLoginRiskIPWhitelist(context.Context, *CheckLoginRiskIPWhitelistRequest) (*CheckLoginRiskIPWhitelistResponse, error)
|
||||
GetRegisterRiskConfig(context.Context, *GetRegisterRiskConfigRequest) (*GetRegisterRiskConfigResponse, error)
|
||||
UpdateRegisterRiskConfig(context.Context, *UpdateRegisterRiskConfigRequest) (*UpdateRegisterRiskConfigResponse, error)
|
||||
AppHeartbeat(context.Context, *AppHeartbeatRequest) (*AppHeartbeatResponse, error)
|
||||
mustEmbedUnimplementedAuthServiceServer()
|
||||
}
|
||||
@ -194,6 +220,12 @@ func (UnimplementedAuthServiceServer) RecordLoginBlocked(context.Context, *Recor
|
||||
func (UnimplementedAuthServiceServer) CheckLoginRiskIPWhitelist(context.Context, *CheckLoginRiskIPWhitelistRequest) (*CheckLoginRiskIPWhitelistResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CheckLoginRiskIPWhitelist not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) GetRegisterRiskConfig(context.Context, *GetRegisterRiskConfigRequest) (*GetRegisterRiskConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetRegisterRiskConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) UpdateRegisterRiskConfig(context.Context, *UpdateRegisterRiskConfigRequest) (*UpdateRegisterRiskConfigResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method UpdateRegisterRiskConfig not implemented")
|
||||
}
|
||||
func (UnimplementedAuthServiceServer) AppHeartbeat(context.Context, *AppHeartbeatRequest) (*AppHeartbeatResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method AppHeartbeat not implemented")
|
||||
}
|
||||
@ -362,6 +394,42 @@ func _AuthService_CheckLoginRiskIPWhitelist_Handler(srv interface{}, ctx context
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthService_GetRegisterRiskConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetRegisterRiskConfigRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).GetRegisterRiskConfig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_GetRegisterRiskConfig_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).GetRegisterRiskConfig(ctx, req.(*GetRegisterRiskConfigRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthService_UpdateRegisterRiskConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(UpdateRegisterRiskConfigRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(AuthServiceServer).UpdateRegisterRiskConfig(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: AuthService_UpdateRegisterRiskConfig_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(AuthServiceServer).UpdateRegisterRiskConfig(ctx, req.(*UpdateRegisterRiskConfigRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _AuthService_AppHeartbeat_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(AppHeartbeatRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -419,6 +487,14 @@ var AuthService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "CheckLoginRiskIPWhitelist",
|
||||
Handler: _AuthService_CheckLoginRiskIPWhitelist_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetRegisterRiskConfig",
|
||||
Handler: _AuthService_GetRegisterRiskConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "UpdateRegisterRiskConfig",
|
||||
Handler: _AuthService_UpdateRegisterRiskConfig_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "AppHeartbeat",
|
||||
Handler: _AuthService_AppHeartbeat_Handler,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1316,6 +1316,44 @@ message CreateH5RechargeOrderRequest {
|
||||
string payer_email = 17;
|
||||
}
|
||||
|
||||
message CreateTemporaryRechargeOrderRequest {
|
||||
string request_id = 1;
|
||||
string app_code = 2;
|
||||
string command_id = 3;
|
||||
int64 coin_amount = 4;
|
||||
int64 usd_minor_amount = 5;
|
||||
string provider_code = 6;
|
||||
int64 payment_method_id = 7;
|
||||
string return_url = 8;
|
||||
string notify_url = 9;
|
||||
string client_ip = 10;
|
||||
string language = 11;
|
||||
string payer_name = 12;
|
||||
string payer_account = 13;
|
||||
string payer_email = 14;
|
||||
}
|
||||
|
||||
message GetTemporaryRechargeOrderRequest {
|
||||
string request_id = 1;
|
||||
string app_code = 2;
|
||||
string order_id = 3;
|
||||
}
|
||||
|
||||
message ListTemporaryRechargeOrdersRequest {
|
||||
string request_id = 1;
|
||||
string app_code = 2;
|
||||
string status = 3;
|
||||
string provider_code = 4;
|
||||
string keyword = 5;
|
||||
int32 page = 6;
|
||||
int32 page_size = 7;
|
||||
}
|
||||
|
||||
message ListTemporaryRechargeOrdersResponse {
|
||||
repeated ExternalRechargeOrder orders = 1;
|
||||
int64 total = 2;
|
||||
}
|
||||
|
||||
message SubmitH5RechargeTxRequest {
|
||||
string request_id = 1;
|
||||
string app_code = 2;
|
||||
@ -2026,6 +2064,9 @@ service WalletService {
|
||||
rpc UpdateThirdPartyPaymentRate(UpdateThirdPartyPaymentRateRequest) returns (ThirdPartyPaymentMethodResponse);
|
||||
rpc ListH5RechargeOptions(H5RechargeOptionsRequest) returns (H5RechargeOptionsResponse);
|
||||
rpc CreateH5RechargeOrder(CreateH5RechargeOrderRequest) returns (H5RechargeOrderResponse);
|
||||
rpc CreateTemporaryRechargeOrder(CreateTemporaryRechargeOrderRequest) returns (H5RechargeOrderResponse);
|
||||
rpc GetTemporaryRechargeOrder(GetTemporaryRechargeOrderRequest) returns (H5RechargeOrderResponse);
|
||||
rpc ListTemporaryRechargeOrders(ListTemporaryRechargeOrdersRequest) returns (ListTemporaryRechargeOrdersResponse);
|
||||
rpc SubmitH5RechargeTx(SubmitH5RechargeTxRequest) returns (H5RechargeOrderResponse);
|
||||
rpc GetH5RechargeOrder(GetH5RechargeOrderRequest) returns (H5RechargeOrderResponse);
|
||||
rpc HandleMifapayNotify(HandleMifapayNotifyRequest) returns (HandleMifapayNotifyResponse);
|
||||
|
||||
@ -258,6 +258,9 @@ const (
|
||||
WalletService_UpdateThirdPartyPaymentRate_FullMethodName = "/hyapp.wallet.v1.WalletService/UpdateThirdPartyPaymentRate"
|
||||
WalletService_ListH5RechargeOptions_FullMethodName = "/hyapp.wallet.v1.WalletService/ListH5RechargeOptions"
|
||||
WalletService_CreateH5RechargeOrder_FullMethodName = "/hyapp.wallet.v1.WalletService/CreateH5RechargeOrder"
|
||||
WalletService_CreateTemporaryRechargeOrder_FullMethodName = "/hyapp.wallet.v1.WalletService/CreateTemporaryRechargeOrder"
|
||||
WalletService_GetTemporaryRechargeOrder_FullMethodName = "/hyapp.wallet.v1.WalletService/GetTemporaryRechargeOrder"
|
||||
WalletService_ListTemporaryRechargeOrders_FullMethodName = "/hyapp.wallet.v1.WalletService/ListTemporaryRechargeOrders"
|
||||
WalletService_SubmitH5RechargeTx_FullMethodName = "/hyapp.wallet.v1.WalletService/SubmitH5RechargeTx"
|
||||
WalletService_GetH5RechargeOrder_FullMethodName = "/hyapp.wallet.v1.WalletService/GetH5RechargeOrder"
|
||||
WalletService_HandleMifapayNotify_FullMethodName = "/hyapp.wallet.v1.WalletService/HandleMifapayNotify"
|
||||
@ -352,6 +355,9 @@ type WalletServiceClient interface {
|
||||
UpdateThirdPartyPaymentRate(ctx context.Context, in *UpdateThirdPartyPaymentRateRequest, opts ...grpc.CallOption) (*ThirdPartyPaymentMethodResponse, error)
|
||||
ListH5RechargeOptions(ctx context.Context, in *H5RechargeOptionsRequest, opts ...grpc.CallOption) (*H5RechargeOptionsResponse, error)
|
||||
CreateH5RechargeOrder(ctx context.Context, in *CreateH5RechargeOrderRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error)
|
||||
CreateTemporaryRechargeOrder(ctx context.Context, in *CreateTemporaryRechargeOrderRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error)
|
||||
GetTemporaryRechargeOrder(ctx context.Context, in *GetTemporaryRechargeOrderRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error)
|
||||
ListTemporaryRechargeOrders(ctx context.Context, in *ListTemporaryRechargeOrdersRequest, opts ...grpc.CallOption) (*ListTemporaryRechargeOrdersResponse, error)
|
||||
SubmitH5RechargeTx(ctx context.Context, in *SubmitH5RechargeTxRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error)
|
||||
GetH5RechargeOrder(ctx context.Context, in *GetH5RechargeOrderRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error)
|
||||
HandleMifapayNotify(ctx context.Context, in *HandleMifapayNotifyRequest, opts ...grpc.CallOption) (*HandleMifapayNotifyResponse, error)
|
||||
@ -961,6 +967,36 @@ func (c *walletServiceClient) CreateH5RechargeOrder(ctx context.Context, in *Cre
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) CreateTemporaryRechargeOrder(ctx context.Context, in *CreateTemporaryRechargeOrderRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(H5RechargeOrderResponse)
|
||||
err := c.cc.Invoke(ctx, WalletService_CreateTemporaryRechargeOrder_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) GetTemporaryRechargeOrder(ctx context.Context, in *GetTemporaryRechargeOrderRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(H5RechargeOrderResponse)
|
||||
err := c.cc.Invoke(ctx, WalletService_GetTemporaryRechargeOrder_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) ListTemporaryRechargeOrders(ctx context.Context, in *ListTemporaryRechargeOrdersRequest, opts ...grpc.CallOption) (*ListTemporaryRechargeOrdersResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ListTemporaryRechargeOrdersResponse)
|
||||
err := c.cc.Invoke(ctx, WalletService_ListTemporaryRechargeOrders_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *walletServiceClient) SubmitH5RechargeTx(ctx context.Context, in *SubmitH5RechargeTxRequest, opts ...grpc.CallOption) (*H5RechargeOrderResponse, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(H5RechargeOrderResponse)
|
||||
@ -1314,6 +1350,9 @@ type WalletServiceServer interface {
|
||||
UpdateThirdPartyPaymentRate(context.Context, *UpdateThirdPartyPaymentRateRequest) (*ThirdPartyPaymentMethodResponse, error)
|
||||
ListH5RechargeOptions(context.Context, *H5RechargeOptionsRequest) (*H5RechargeOptionsResponse, error)
|
||||
CreateH5RechargeOrder(context.Context, *CreateH5RechargeOrderRequest) (*H5RechargeOrderResponse, error)
|
||||
CreateTemporaryRechargeOrder(context.Context, *CreateTemporaryRechargeOrderRequest) (*H5RechargeOrderResponse, error)
|
||||
GetTemporaryRechargeOrder(context.Context, *GetTemporaryRechargeOrderRequest) (*H5RechargeOrderResponse, error)
|
||||
ListTemporaryRechargeOrders(context.Context, *ListTemporaryRechargeOrdersRequest) (*ListTemporaryRechargeOrdersResponse, error)
|
||||
SubmitH5RechargeTx(context.Context, *SubmitH5RechargeTxRequest) (*H5RechargeOrderResponse, error)
|
||||
GetH5RechargeOrder(context.Context, *GetH5RechargeOrderRequest) (*H5RechargeOrderResponse, error)
|
||||
HandleMifapayNotify(context.Context, *HandleMifapayNotifyRequest) (*HandleMifapayNotifyResponse, error)
|
||||
@ -1524,6 +1563,15 @@ func (UnimplementedWalletServiceServer) ListH5RechargeOptions(context.Context, *
|
||||
func (UnimplementedWalletServiceServer) CreateH5RechargeOrder(context.Context, *CreateH5RechargeOrderRequest) (*H5RechargeOrderResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateH5RechargeOrder not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) CreateTemporaryRechargeOrder(context.Context, *CreateTemporaryRechargeOrderRequest) (*H5RechargeOrderResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method CreateTemporaryRechargeOrder not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) GetTemporaryRechargeOrder(context.Context, *GetTemporaryRechargeOrderRequest) (*H5RechargeOrderResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetTemporaryRechargeOrder not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) ListTemporaryRechargeOrders(context.Context, *ListTemporaryRechargeOrdersRequest) (*ListTemporaryRechargeOrdersResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method ListTemporaryRechargeOrders not implemented")
|
||||
}
|
||||
func (UnimplementedWalletServiceServer) SubmitH5RechargeTx(context.Context, *SubmitH5RechargeTxRequest) (*H5RechargeOrderResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SubmitH5RechargeTx not implemented")
|
||||
}
|
||||
@ -2658,6 +2706,60 @@ func _WalletService_CreateH5RechargeOrder_Handler(srv interface{}, ctx context.C
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_CreateTemporaryRechargeOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CreateTemporaryRechargeOrderRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WalletServiceServer).CreateTemporaryRechargeOrder(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WalletService_CreateTemporaryRechargeOrder_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WalletServiceServer).CreateTemporaryRechargeOrder(ctx, req.(*CreateTemporaryRechargeOrderRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_GetTemporaryRechargeOrder_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(GetTemporaryRechargeOrderRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WalletServiceServer).GetTemporaryRechargeOrder(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WalletService_GetTemporaryRechargeOrder_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WalletServiceServer).GetTemporaryRechargeOrder(ctx, req.(*GetTemporaryRechargeOrderRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_ListTemporaryRechargeOrders_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ListTemporaryRechargeOrdersRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(WalletServiceServer).ListTemporaryRechargeOrders(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: WalletService_ListTemporaryRechargeOrders_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(WalletServiceServer).ListTemporaryRechargeOrders(ctx, req.(*ListTemporaryRechargeOrdersRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _WalletService_SubmitH5RechargeTx_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SubmitH5RechargeTxRequest)
|
||||
if err := dec(in); err != nil {
|
||||
@ -3415,6 +3517,18 @@ var WalletService_ServiceDesc = grpc.ServiceDesc{
|
||||
MethodName: "CreateH5RechargeOrder",
|
||||
Handler: _WalletService_CreateH5RechargeOrder_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "CreateTemporaryRechargeOrder",
|
||||
Handler: _WalletService_CreateTemporaryRechargeOrder_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "GetTemporaryRechargeOrder",
|
||||
Handler: _WalletService_GetTemporaryRechargeOrder_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "ListTemporaryRechargeOrders",
|
||||
Handler: _WalletService_ListTemporaryRechargeOrders_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SubmitH5RechargeTx",
|
||||
Handler: _WalletService_SubmitH5RechargeTx_Handler,
|
||||
|
||||
@ -59,6 +59,7 @@ import (
|
||||
registrationrewardmodule "hyapp-admin-server/internal/modules/registrationreward"
|
||||
reportmodule "hyapp-admin-server/internal/modules/report"
|
||||
resourcemodule "hyapp-admin-server/internal/modules/resource"
|
||||
riskconfigmodule "hyapp-admin-server/internal/modules/riskconfig"
|
||||
roomadminmodule "hyapp-admin-server/internal/modules/roomadmin"
|
||||
roomrocketmodule "hyapp-admin-server/internal/modules/roomrocket"
|
||||
roomturnoverrewardmodule "hyapp-admin-server/internal/modules/roomturnoverreward"
|
||||
@ -293,6 +294,7 @@ func main() {
|
||||
RegistrationReward: registrationrewardmodule.New(activityclient.NewGRPC(activityConn), userDB, auditHandler),
|
||||
RegionBlock: regionblockmodule.New(userDB, auditHandler),
|
||||
Resource: resourcemodule.New(walletclient.NewGRPC(walletConn), store, userDB, cfg.WalletService.RequestTimeout, auditHandler),
|
||||
RiskConfig: riskconfigmodule.New(userclient.NewGRPC(userConn), auditHandler),
|
||||
RoomAdmin: roomadminmodule.New(userDB, store, roomClient, robotClient, auditHandler),
|
||||
RoomRocket: roomrocketmodule.New(roomClient, auditHandler),
|
||||
RoomTurnoverReward: roomturnoverrewardmodule.New(activityclient.NewGRPC(activityConn), userDB, auditHandler),
|
||||
|
||||
@ -15,6 +15,8 @@ type Client interface {
|
||||
BatchGetUsers(ctx context.Context, req BatchGetUsersRequest) (map[int64]*User, error)
|
||||
AdminChangeUserCountry(ctx context.Context, req AdminChangeUserCountryRequest) (*ChangeUserCountryResult, error)
|
||||
SetUserStatus(ctx context.Context, req SetUserStatusRequest) (*SetUserStatusResult, error)
|
||||
GetRegisterRiskConfig(ctx context.Context, req GetRegisterRiskConfigRequest) (*RegisterRiskConfig, error)
|
||||
UpdateRegisterRiskConfig(ctx context.Context, req UpdateRegisterRiskConfigRequest) (*RegisterRiskConfig, error)
|
||||
ResolveDisplayUserID(ctx context.Context, req ResolveDisplayUserIDRequest) (*UserIdentity, error)
|
||||
ListPrettyDisplayIDPools(ctx context.Context, req ListPrettyDisplayIDPoolsRequest) ([]*PrettyDisplayIDPool, int64, error)
|
||||
CreatePrettyDisplayIDPool(ctx context.Context, req PrettyDisplayIDPoolRequest) (*PrettyDisplayIDPool, error)
|
||||
@ -117,6 +119,25 @@ type SetUserStatusResult struct {
|
||||
RoomEvictError string `json:"roomEvictError,omitempty"`
|
||||
}
|
||||
|
||||
type GetRegisterRiskConfigRequest struct {
|
||||
RequestID string
|
||||
Caller string
|
||||
}
|
||||
|
||||
type UpdateRegisterRiskConfigRequest struct {
|
||||
RequestID string
|
||||
Caller string
|
||||
MaxAccountsPerDevice int32
|
||||
OperatorAdminID int64
|
||||
}
|
||||
|
||||
type RegisterRiskConfig struct {
|
||||
AppCode string `json:"appCode"`
|
||||
MaxAccountsPerDevice int32 `json:"maxAccountsPerDevice"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
UpdatedByAdminID int64 `json:"updatedByAdminId"`
|
||||
}
|
||||
|
||||
type ResolveDisplayUserIDRequest struct {
|
||||
RequestID string
|
||||
Caller string
|
||||
@ -240,6 +261,28 @@ func (c *GRPCClient) GetUser(ctx context.Context, req GetUserRequest) (*User, er
|
||||
return fromProtoUser(resp.GetUser()), nil
|
||||
}
|
||||
|
||||
func (c *GRPCClient) GetRegisterRiskConfig(ctx context.Context, req GetRegisterRiskConfigRequest) (*RegisterRiskConfig, error) {
|
||||
resp, err := c.authClient.GetRegisterRiskConfig(ctx, &userv1.GetRegisterRiskConfigRequest{
|
||||
Meta: requestMeta(ctx, req.RequestID, req.Caller),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fromProtoRegisterRiskConfig(resp.GetConfig()), nil
|
||||
}
|
||||
|
||||
func (c *GRPCClient) UpdateRegisterRiskConfig(ctx context.Context, req UpdateRegisterRiskConfigRequest) (*RegisterRiskConfig, error) {
|
||||
resp, err := c.authClient.UpdateRegisterRiskConfig(ctx, &userv1.UpdateRegisterRiskConfigRequest{
|
||||
Meta: requestMeta(ctx, req.RequestID, req.Caller),
|
||||
MaxAccountsPerDevice: req.MaxAccountsPerDevice,
|
||||
OperatorAdminId: req.OperatorAdminID,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return fromProtoRegisterRiskConfig(resp.GetConfig()), nil
|
||||
}
|
||||
|
||||
// BatchGetUsers 复用 user-service 主数据 RPC,让后台列表只做展示聚合,不复制用户资料到游戏库。
|
||||
func (c *GRPCClient) BatchGetUsers(ctx context.Context, req BatchGetUsersRequest) (map[int64]*User, error) {
|
||||
resp, err := c.client.BatchGetUsers(ctx, &userv1.BatchGetUsersRequest{
|
||||
@ -326,6 +369,18 @@ func (c *GRPCClient) ResolveDisplayUserID(ctx context.Context, req ResolveDispla
|
||||
return fromProtoUserIdentity(resp.GetIdentity()), nil
|
||||
}
|
||||
|
||||
func fromProtoRegisterRiskConfig(config *userv1.RegisterRiskConfig) *RegisterRiskConfig {
|
||||
if config == nil {
|
||||
return nil
|
||||
}
|
||||
return &RegisterRiskConfig{
|
||||
AppCode: config.GetAppCode(),
|
||||
MaxAccountsPerDevice: config.GetMaxAccountsPerDevice(),
|
||||
UpdatedAtMs: config.GetUpdatedAtMs(),
|
||||
UpdatedByAdminID: config.GetUpdatedByAdminId(),
|
||||
}
|
||||
}
|
||||
|
||||
func fromProtoUser(user *userv1.User) *User {
|
||||
if user == nil {
|
||||
return nil
|
||||
@ -488,71 +543,71 @@ type SetAgencyJoinEnabledRequest struct {
|
||||
}
|
||||
|
||||
type BDProfile struct {
|
||||
UserID int64 `json:"userId,string"`
|
||||
Role string `json:"role"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
ParentLeaderUserID int64 `json:"parentLeaderUserId,string"`
|
||||
PositionAlias string `json:"positionAlias"`
|
||||
Status string `json:"status"`
|
||||
CreatedByUserID int64 `json:"createdByUserId,string"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
DisplayUserID string `json:"displayUserId"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
RegionName string `json:"regionName"`
|
||||
ParentLeaderDisplayID string `json:"parentLeaderDisplayUserId"`
|
||||
ParentLeaderUsername string `json:"parentLeaderUsername"`
|
||||
ParentLeaderAvatar string `json:"parentLeaderAvatar"`
|
||||
CreatedByDisplayUserID string `json:"createdByDisplayUserId"`
|
||||
CreatedByUsername string `json:"createdByUsername"`
|
||||
CreatedByAvatar string `json:"createdByAvatar"`
|
||||
SubBDCount int64 `json:"subBdCount"`
|
||||
UserID int64 `json:"userId,string"`
|
||||
Role string `json:"role"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
ParentLeaderUserID int64 `json:"parentLeaderUserId,string"`
|
||||
PositionAlias string `json:"positionAlias"`
|
||||
Status string `json:"status"`
|
||||
CreatedByUserID int64 `json:"createdByUserId,string"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
DisplayUserID string `json:"displayUserId"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
RegionName string `json:"regionName"`
|
||||
ParentLeaderDisplayID string `json:"parentLeaderDisplayUserId"`
|
||||
ParentLeaderUsername string `json:"parentLeaderUsername"`
|
||||
ParentLeaderAvatar string `json:"parentLeaderAvatar"`
|
||||
CreatedByDisplayUserID string `json:"createdByDisplayUserId"`
|
||||
CreatedByUsername string `json:"createdByUsername"`
|
||||
CreatedByAvatar string `json:"createdByAvatar"`
|
||||
SubBDCount int64 `json:"subBdCount"`
|
||||
SalaryWallet SalaryWallet `json:"salaryWallet"`
|
||||
}
|
||||
|
||||
type Agency struct {
|
||||
AgencyID int64 `json:"agencyId,string"`
|
||||
OwnerUserID int64 `json:"ownerUserId,string"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
ParentBDUserID int64 `json:"parentBdUserId,string"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
JoinEnabled bool `json:"joinEnabled"`
|
||||
MaxHosts int32 `json:"maxHosts"`
|
||||
CreatedByUserID int64 `json:"createdByUserId,string"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
OwnerDisplayUserID string `json:"ownerDisplayUserId"`
|
||||
OwnerUsername string `json:"ownerUsername"`
|
||||
OwnerAvatar string `json:"ownerAvatar"`
|
||||
ParentBDDisplayUserID string `json:"parentBdDisplayUserId"`
|
||||
ParentBDUsername string `json:"parentBdUsername"`
|
||||
ParentBDAvatar string `json:"parentBdAvatar"`
|
||||
RegionName string `json:"regionName"`
|
||||
AgencyID int64 `json:"agencyId,string"`
|
||||
OwnerUserID int64 `json:"ownerUserId,string"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
ParentBDUserID int64 `json:"parentBdUserId,string"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
JoinEnabled bool `json:"joinEnabled"`
|
||||
MaxHosts int32 `json:"maxHosts"`
|
||||
CreatedByUserID int64 `json:"createdByUserId,string"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
OwnerDisplayUserID string `json:"ownerDisplayUserId"`
|
||||
OwnerUsername string `json:"ownerUsername"`
|
||||
OwnerAvatar string `json:"ownerAvatar"`
|
||||
ParentBDDisplayUserID string `json:"parentBdDisplayUserId"`
|
||||
ParentBDUsername string `json:"parentBdUsername"`
|
||||
ParentBDAvatar string `json:"parentBdAvatar"`
|
||||
RegionName string `json:"regionName"`
|
||||
SalaryWallet SalaryWallet `json:"salaryWallet"`
|
||||
}
|
||||
|
||||
type HostProfile struct {
|
||||
UserID int64 `json:"userId,string"`
|
||||
Status string `json:"status"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
CurrentAgencyID int64 `json:"currentAgencyId,string"`
|
||||
CurrentMembershipID int64 `json:"currentMembershipId,string"`
|
||||
Source string `json:"source"`
|
||||
FirstBecameHostAtMs int64 `json:"firstBecameHostAtMs"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
DisplayUserID string `json:"displayUserId"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
RegionName string `json:"regionName"`
|
||||
CurrentAgencyName string `json:"currentAgencyName"`
|
||||
Diamond int64 `json:"diamond"`
|
||||
CurrentAgencyOwnerUserID int64 `json:"currentAgencyOwnerUserId,string"`
|
||||
CurrentAgencyOwnerDisplayUserID string `json:"currentAgencyOwnerDisplayUserId"`
|
||||
CurrentAgencyOwnerUsername string `json:"currentAgencyOwnerUsername"`
|
||||
CurrentAgencyOwnerAvatar string `json:"currentAgencyOwnerAvatar"`
|
||||
UserID int64 `json:"userId,string"`
|
||||
Status string `json:"status"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
CurrentAgencyID int64 `json:"currentAgencyId,string"`
|
||||
CurrentMembershipID int64 `json:"currentMembershipId,string"`
|
||||
Source string `json:"source"`
|
||||
FirstBecameHostAtMs int64 `json:"firstBecameHostAtMs"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
DisplayUserID string `json:"displayUserId"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
RegionName string `json:"regionName"`
|
||||
CurrentAgencyName string `json:"currentAgencyName"`
|
||||
Diamond int64 `json:"diamond"`
|
||||
CurrentAgencyOwnerUserID int64 `json:"currentAgencyOwnerUserId,string"`
|
||||
CurrentAgencyOwnerDisplayUserID string `json:"currentAgencyOwnerDisplayUserId"`
|
||||
CurrentAgencyOwnerUsername string `json:"currentAgencyOwnerUsername"`
|
||||
CurrentAgencyOwnerAvatar string `json:"currentAgencyOwnerAvatar"`
|
||||
SalaryWallet SalaryWallet `json:"salaryWallet"`
|
||||
}
|
||||
|
||||
|
||||
@ -40,6 +40,8 @@ type Client interface {
|
||||
AdminCreditCoinSellerStock(ctx context.Context, req *walletv1.AdminCreditCoinSellerStockRequest) (*walletv1.AdminCreditCoinSellerStockResponse, error)
|
||||
ListRechargeBills(ctx context.Context, req *walletv1.ListRechargeBillsRequest) (*walletv1.ListRechargeBillsResponse, error)
|
||||
ListThirdPartyPaymentChannels(ctx context.Context, req *walletv1.ListThirdPartyPaymentChannelsRequest) (*walletv1.ListThirdPartyPaymentChannelsResponse, error)
|
||||
GetTemporaryRechargeOrder(ctx context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error)
|
||||
ListTemporaryRechargeOrders(ctx context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error)
|
||||
SetThirdPartyPaymentMethodStatus(ctx context.Context, req *walletv1.SetThirdPartyPaymentMethodStatusRequest) (*walletv1.ThirdPartyPaymentMethodResponse, error)
|
||||
UpdateThirdPartyPaymentRate(ctx context.Context, req *walletv1.UpdateThirdPartyPaymentRateRequest) (*walletv1.ThirdPartyPaymentMethodResponse, error)
|
||||
ListAdminRechargeProducts(ctx context.Context, req *walletv1.ListAdminRechargeProductsRequest) (*walletv1.ListAdminRechargeProductsResponse, error)
|
||||
@ -184,6 +186,14 @@ func (c *GRPCClient) ListThirdPartyPaymentChannels(ctx context.Context, req *wal
|
||||
return c.client.ListThirdPartyPaymentChannels(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) GetTemporaryRechargeOrder(ctx context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
return c.client.GetTemporaryRechargeOrder(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) ListTemporaryRechargeOrders(ctx context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error) {
|
||||
return c.client.ListTemporaryRechargeOrders(ctx, req)
|
||||
}
|
||||
|
||||
func (c *GRPCClient) SetThirdPartyPaymentMethodStatus(ctx context.Context, req *walletv1.SetThirdPartyPaymentMethodStatusRequest) (*walletv1.ThirdPartyPaymentMethodResponse, error) {
|
||||
return c.client.SetThirdPartyPaymentMethodStatus(ctx, req)
|
||||
}
|
||||
|
||||
@ -33,24 +33,67 @@ type Service struct {
|
||||
}
|
||||
|
||||
type AppUser struct {
|
||||
Avatar string `json:"avatar"`
|
||||
Coin int64 `json:"coin"`
|
||||
Country string `json:"country"`
|
||||
CountryDisplayName string `json:"countryDisplayName"`
|
||||
CountryName string `json:"countryName"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
DefaultDisplayUserID string `json:"defaultDisplayUserId"`
|
||||
DisplayUserID string `json:"displayUserId"`
|
||||
Gender string `json:"gender"`
|
||||
LastActiveAtMs int64 `json:"lastActiveAtMs"`
|
||||
PrettyDisplayUserID string `json:"prettyDisplayUserId"`
|
||||
PrettyID string `json:"prettyId"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
RegionName string `json:"regionName"`
|
||||
Status string `json:"status"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
UserID string `json:"userId"`
|
||||
Username string `json:"username"`
|
||||
Avatar string `json:"avatar"`
|
||||
Balances []AppUserAssetBalance `json:"balances,omitempty"`
|
||||
Coin int64 `json:"coin"`
|
||||
Country string `json:"country"`
|
||||
CountryDisplayName string `json:"countryDisplayName"`
|
||||
CountryName string `json:"countryName"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
DefaultDisplayUserID string `json:"defaultDisplayUserId"`
|
||||
Diamond int64 `json:"diamond"`
|
||||
DisplayUserID string `json:"displayUserId"`
|
||||
EquippedResources []AppUserResource `json:"equippedResources,omitempty"`
|
||||
Gender string `json:"gender"`
|
||||
LastActiveAtMs int64 `json:"lastActiveAtMs"`
|
||||
PrettyDisplayUserID string `json:"prettyDisplayUserId"`
|
||||
PrettyID string `json:"prettyId"`
|
||||
RegionID int64 `json:"regionId"`
|
||||
RegionName string `json:"regionName"`
|
||||
Resources []AppUserResource `json:"resources,omitempty"`
|
||||
Status string `json:"status"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
UserID string `json:"userId"`
|
||||
Username string `json:"username"`
|
||||
VIP AppUserVIP `json:"vip"`
|
||||
}
|
||||
|
||||
type AppUserAssetBalance struct {
|
||||
AssetType string `json:"assetType"`
|
||||
AvailableAmount int64 `json:"availableAmount"`
|
||||
FrozenAmount int64 `json:"frozenAmount"`
|
||||
TotalAmount int64 `json:"totalAmount"`
|
||||
Version int64 `json:"version"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
}
|
||||
|
||||
type AppUserVIP struct {
|
||||
Level int32 `json:"level"`
|
||||
Name string `json:"name"`
|
||||
Active bool `json:"active"`
|
||||
StartedAtMs int64 `json:"startedAtMs"`
|
||||
ExpiresAtMs int64 `json:"expiresAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
}
|
||||
|
||||
type AppUserResource struct {
|
||||
EntitlementID string `json:"entitlementId"`
|
||||
ResourceID int64 `json:"resourceId"`
|
||||
ResourceCode string `json:"resourceCode"`
|
||||
ResourceType string `json:"resourceType"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Quantity int64 `json:"quantity"`
|
||||
RemainingQuantity int64 `json:"remainingQuantity"`
|
||||
EffectiveAtMs int64 `json:"effectiveAtMs"`
|
||||
ExpiresAtMs int64 `json:"expiresAtMs"`
|
||||
SourceGrantID string `json:"sourceGrantId"`
|
||||
AssetURL string `json:"assetUrl"`
|
||||
PreviewURL string `json:"previewUrl"`
|
||||
AnimationURL string `json:"animationUrl"`
|
||||
Equipped bool `json:"equipped"`
|
||||
CreatedAtMs int64 `json:"createdAtMs"`
|
||||
UpdatedAtMs int64 `json:"updatedAtMs"`
|
||||
}
|
||||
|
||||
type SetUserStatusResult struct {
|
||||
@ -146,6 +189,9 @@ func (s *Service) ListUsers(ctx context.Context, query listQuery) ([]AppUser, in
|
||||
if err := s.fillBalances(ctx, items, userIDs); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if err := s.fillVIPLevels(ctx, items, userIDs); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
@ -206,7 +252,11 @@ func (s *Service) listUsersSortedByCoin(ctx context.Context, query listQuery, wh
|
||||
return nil, err
|
||||
}
|
||||
sortAppUsersByCoin(items, query.SortDirection)
|
||||
return paginateAppUsers(items, query.Page, query.PageSize), nil
|
||||
pagedItems := paginateAppUsers(items, query.Page, query.PageSize)
|
||||
if err := s.fillVIPLevels(ctx, pagedItems, appUserNumericIDs(pagedItems)); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pagedItems, nil
|
||||
}
|
||||
|
||||
func scanAppUserRows(rows *sql.Rows, capacity int) ([]AppUser, []int64, error) {
|
||||
@ -327,6 +377,12 @@ func (s *Service) GetUser(ctx context.Context, userID int64) (AppUser, error) {
|
||||
if err := s.fillBalances(ctx, items, []int64{userID}); err != nil {
|
||||
return AppUser{}, err
|
||||
}
|
||||
if err := s.fillVIPLevels(ctx, items, []int64{userID}); err != nil {
|
||||
return AppUser{}, err
|
||||
}
|
||||
if err := s.fillUserResources(ctx, items, userID); err != nil {
|
||||
return AppUser{}, err
|
||||
}
|
||||
return items[0], nil
|
||||
}
|
||||
|
||||
@ -517,26 +573,31 @@ func (s *Service) fillBalances(ctx context.Context, items []AppUser, userIDs []i
|
||||
}
|
||||
// 用户列表金币排序会对完整筛选集补余额,按块查询可以避免 IN 参数过长导致后台列表失败。
|
||||
chunk := userIDs[start:end]
|
||||
placeholders := strings.TrimRight(strings.Repeat("?,", len(chunk)), ",")
|
||||
args := make([]any, 0, len(chunk)+2)
|
||||
args := make([]any, 0, len(chunk)+1)
|
||||
args = append(args, appCode)
|
||||
for _, id := range chunk {
|
||||
args = append(args, id)
|
||||
}
|
||||
args = append(args, "COIN")
|
||||
rows, err := s.walletDB.QueryContext(ctx, fmt.Sprintf(`
|
||||
SELECT user_id, asset_type, available_amount
|
||||
SELECT user_id, asset_type, available_amount, frozen_amount, version, updated_at_ms
|
||||
FROM wallet_accounts
|
||||
WHERE app_code = ? AND user_id IN (%s) AND asset_type = ?
|
||||
`, placeholders), args...)
|
||||
WHERE app_code = ? AND user_id IN (%s)
|
||||
ORDER BY user_id ASC, asset_type ASC
|
||||
`, placeholders(len(chunk))), args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for rows.Next() {
|
||||
var userID int64
|
||||
var assetType string
|
||||
var amount int64
|
||||
if err := rows.Scan(&userID, &assetType, &amount); err != nil {
|
||||
var balance AppUserAssetBalance
|
||||
if err := rows.Scan(
|
||||
&userID,
|
||||
&balance.AssetType,
|
||||
&balance.AvailableAmount,
|
||||
&balance.FrozenAmount,
|
||||
&balance.Version,
|
||||
&balance.UpdatedAtMs,
|
||||
); err != nil {
|
||||
_ = rows.Close()
|
||||
return err
|
||||
}
|
||||
@ -544,9 +605,15 @@ func (s *Service) fillBalances(ctx context.Context, items []AppUser, userIDs []i
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
switch strings.ToUpper(assetType) {
|
||||
balance.AssetType = strings.ToUpper(strings.TrimSpace(balance.AssetType))
|
||||
balance.TotalAmount = balance.AvailableAmount + balance.FrozenAmount
|
||||
// 钱包资产明细作为详情页“全部资产”的余额来源;金币和钻石仍同步到顶层字段,兼容列表排序和旧页面读取。
|
||||
items[i].Balances = append(items[i].Balances, balance)
|
||||
switch balance.AssetType {
|
||||
case "COIN":
|
||||
items[i].Coin = amount
|
||||
items[i].Coin = balance.AvailableAmount
|
||||
case "DIAMOND":
|
||||
items[i].Diamond = balance.AvailableAmount
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
@ -560,6 +627,138 @@ func (s *Service) fillBalances(ctx context.Context, items []AppUser, userIDs []i
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) fillVIPLevels(ctx context.Context, items []AppUser, userIDs []int64) error {
|
||||
if s.walletDB == nil || len(userIDs) == 0 {
|
||||
return nil
|
||||
}
|
||||
index := make(map[int64]int, len(userIDs))
|
||||
for i, id := range userIDs {
|
||||
index[id] = i
|
||||
}
|
||||
appCode := appctx.FromContext(ctx)
|
||||
nowMs := nowMillis()
|
||||
const chunkSize = 500
|
||||
for start := 0; start < len(userIDs); start += chunkSize {
|
||||
end := start + chunkSize
|
||||
if end > len(userIDs) {
|
||||
end = len(userIDs)
|
||||
}
|
||||
chunk := userIDs[start:end]
|
||||
args := make([]any, 0, len(chunk)+1)
|
||||
args = append(args, appCode)
|
||||
for _, id := range chunk {
|
||||
args = append(args, id)
|
||||
}
|
||||
rows, err := s.walletDB.QueryContext(ctx, fmt.Sprintf(`
|
||||
SELECT m.user_id, m.level, COALESCE(v.name, m.name), m.started_at_ms, m.expires_at_ms, m.updated_at_ms
|
||||
FROM user_vip_memberships m
|
||||
LEFT JOIN vip_levels v ON v.app_code = m.app_code AND v.level = m.level
|
||||
WHERE m.app_code = ? AND m.user_id IN (%s)
|
||||
`, placeholders(len(chunk))), args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for rows.Next() {
|
||||
var userID int64
|
||||
var vip AppUserVIP
|
||||
if err := rows.Scan(&userID, &vip.Level, &vip.Name, &vip.StartedAtMs, &vip.ExpiresAtMs, &vip.UpdatedAtMs); err != nil {
|
||||
_ = rows.Close()
|
||||
return err
|
||||
}
|
||||
i, ok := index[userID]
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// 这里刻意沿用 wallet-service GetMyVip 的展示口径:只看 level 和 expires_at_ms 计算当前 VIP,
|
||||
// 过期会员仍保留历史行,但后台用户列表不展示为有效等级。
|
||||
vip.Active = vip.Level > 0 && vip.ExpiresAtMs > nowMs
|
||||
if !vip.Active {
|
||||
vip.Level = 0
|
||||
vip.Name = ""
|
||||
}
|
||||
items[i].VIP = vip
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
_ = rows.Close()
|
||||
return err
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) fillUserResources(ctx context.Context, items []AppUser, userID int64) error {
|
||||
if s.walletDB == nil || len(items) == 0 || userID <= 0 {
|
||||
return nil
|
||||
}
|
||||
appCode := appctx.FromContext(ctx)
|
||||
nowMs := nowMillis()
|
||||
rows, err := s.walletDB.QueryContext(ctx, `
|
||||
SELECT e.entitlement_id, e.resource_id, r.resource_code, r.resource_type, r.name, e.status,
|
||||
e.quantity, e.remaining_quantity, e.effective_at_ms, e.expires_at_ms, e.source_grant_id,
|
||||
COALESCE(r.asset_url, ''), COALESCE(r.preview_url, ''), COALESCE(r.animation_url, ''),
|
||||
CASE WHEN eq.entitlement_id IS NULL THEN FALSE ELSE TRUE END AS equipped,
|
||||
e.created_at_ms, e.updated_at_ms
|
||||
FROM user_resource_entitlements e
|
||||
JOIN resources r ON r.app_code = e.app_code AND r.resource_id = e.resource_id
|
||||
LEFT JOIN user_resource_equipment eq
|
||||
ON eq.app_code = e.app_code
|
||||
AND eq.user_id = e.user_id
|
||||
AND eq.resource_id = e.resource_id
|
||||
AND eq.entitlement_id = e.entitlement_id
|
||||
WHERE e.app_code = ? AND e.user_id = ?
|
||||
AND e.status = 'active'
|
||||
AND e.effective_at_ms <= ? AND (e.expires_at_ms = 0 OR e.expires_at_ms > ?)
|
||||
AND e.remaining_quantity > 0
|
||||
AND r.status = 'active'
|
||||
ORDER BY equipped DESC, r.resource_type ASC, e.updated_at_ms DESC, e.created_at_ms DESC
|
||||
`, appCode, userID, nowMs, nowMs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
resources := make([]AppUserResource, 0)
|
||||
equipped := make([]AppUserResource, 0)
|
||||
for rows.Next() {
|
||||
var resource AppUserResource
|
||||
if err := rows.Scan(
|
||||
&resource.EntitlementID,
|
||||
&resource.ResourceID,
|
||||
&resource.ResourceCode,
|
||||
&resource.ResourceType,
|
||||
&resource.Name,
|
||||
&resource.Status,
|
||||
&resource.Quantity,
|
||||
&resource.RemainingQuantity,
|
||||
&resource.EffectiveAtMs,
|
||||
&resource.ExpiresAtMs,
|
||||
&resource.SourceGrantID,
|
||||
&resource.AssetURL,
|
||||
&resource.PreviewURL,
|
||||
&resource.AnimationURL,
|
||||
&resource.Equipped,
|
||||
&resource.CreatedAtMs,
|
||||
&resource.UpdatedAtMs,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
resources = append(resources, resource)
|
||||
if resource.Equipped {
|
||||
// 装备状态只从 user_resource_equipment 读取;前端可以直接展示当前佩戴,不需要再按类型猜测。
|
||||
equipped = append(equipped, resource)
|
||||
}
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
items[0].Resources = resources
|
||||
items[0].EquippedResources = equipped
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeListQuery(query listQuery) listQuery {
|
||||
if query.Page < 1 {
|
||||
query.Page = 1
|
||||
@ -737,6 +936,18 @@ func paginateAppUsers(items []AppUser, page int, pageSize int) []AppUser {
|
||||
return items[start:end]
|
||||
}
|
||||
|
||||
func appUserNumericIDs(items []AppUser) []int64 {
|
||||
ids := make([]int64, 0, len(items))
|
||||
for _, item := range items {
|
||||
id, err := strconv.ParseInt(item.UserID, 10, 64)
|
||||
if err != nil || id <= 0 {
|
||||
continue
|
||||
}
|
||||
ids = append(ids, id)
|
||||
}
|
||||
return ids
|
||||
}
|
||||
|
||||
func countRows(ctx context.Context, db *sql.DB, whereSQL string, args ...any) (int64, error) {
|
||||
var total int64
|
||||
err := db.QueryRowContext(ctx, "SELECT COUNT(*) "+whereSQL, args...).Scan(&total)
|
||||
|
||||
@ -96,6 +96,31 @@ type thirdPartyPaymentMethodDTO struct {
|
||||
UpdatedAtMS int64 `json:"updatedAtMs"`
|
||||
}
|
||||
|
||||
type temporaryPaymentLinkDTO struct {
|
||||
OrderID string `json:"orderId"`
|
||||
AppCode string `json:"appCode"`
|
||||
CommandID string `json:"commandId,omitempty"`
|
||||
AudienceType string `json:"audienceType"`
|
||||
ProductName string `json:"productName"`
|
||||
CoinAmount int64 `json:"coinAmount"`
|
||||
USDMinorAmount int64 `json:"usdMinorAmount"`
|
||||
ProviderCode string `json:"providerCode"`
|
||||
PaymentMethodID int64 `json:"paymentMethodId"`
|
||||
CountryCode string `json:"countryCode"`
|
||||
CurrencyCode string `json:"currencyCode"`
|
||||
ProviderAmountMinor int64 `json:"providerAmountMinor"`
|
||||
PayWay string `json:"payWay"`
|
||||
PayType string `json:"payType"`
|
||||
PayURL string `json:"payUrl"`
|
||||
ProviderOrderID string `json:"providerOrderId"`
|
||||
TxHash string `json:"txHash"`
|
||||
Status string `json:"status"`
|
||||
FailureReason string `json:"failureReason"`
|
||||
TransactionID string `json:"transactionId"`
|
||||
CreatedAtMS int64 `json:"createdAtMs"`
|
||||
UpdatedAtMS int64 `json:"updatedAtMs"`
|
||||
}
|
||||
|
||||
func rechargeBillFromProto(item *walletv1.RechargeBill) rechargeBillDTO {
|
||||
if item == nil {
|
||||
return rechargeBillDTO{}
|
||||
@ -247,6 +272,35 @@ func thirdPartyPaymentMethodFromProto(item *walletv1.ThirdPartyPaymentMethod) th
|
||||
}
|
||||
}
|
||||
|
||||
func temporaryPaymentLinkFromProto(item *walletv1.ExternalRechargeOrder) temporaryPaymentLinkDTO {
|
||||
if item == nil {
|
||||
return temporaryPaymentLinkDTO{}
|
||||
}
|
||||
return temporaryPaymentLinkDTO{
|
||||
OrderID: item.GetOrderId(),
|
||||
AppCode: item.GetAppCode(),
|
||||
AudienceType: item.GetAudienceType(),
|
||||
ProductName: item.GetProductName(),
|
||||
CoinAmount: item.GetCoinAmount(),
|
||||
USDMinorAmount: item.GetUsdMinorAmount(),
|
||||
ProviderCode: item.GetProviderCode(),
|
||||
PaymentMethodID: item.GetPaymentMethodId(),
|
||||
CountryCode: item.GetCountryCode(),
|
||||
CurrencyCode: item.GetCurrencyCode(),
|
||||
ProviderAmountMinor: item.GetProviderAmountMinor(),
|
||||
PayWay: item.GetPayWay(),
|
||||
PayType: item.GetPayType(),
|
||||
PayURL: item.GetPayUrl(),
|
||||
ProviderOrderID: item.GetProviderOrderId(),
|
||||
TxHash: item.GetTxHash(),
|
||||
Status: item.GetStatus(),
|
||||
FailureReason: item.GetFailureReason(),
|
||||
TransactionID: item.GetTransactionId(),
|
||||
CreatedAtMS: item.GetCreatedAtMs(),
|
||||
UpdatedAtMS: item.GetUpdatedAtMs(),
|
||||
}
|
||||
}
|
||||
|
||||
func formatUSDTMicro(amount int64) string {
|
||||
if amount <= 0 {
|
||||
return "0"
|
||||
|
||||
@ -261,6 +261,47 @@ func (h *Handler) ListThirdPartyPaymentChannels(c *gin.Context) {
|
||||
response.OK(c, gin.H{"items": items, "total": len(items)})
|
||||
}
|
||||
|
||||
func (h *Handler) ListTemporaryPaymentLinks(c *gin.Context) {
|
||||
options := shared.ListOptions(c)
|
||||
resp, err := h.wallet.ListTemporaryRechargeOrders(c.Request.Context(), &walletv1.ListTemporaryRechargeOrdersRequest{
|
||||
RequestId: middleware.CurrentRequestID(c),
|
||||
AppCode: appctx.FromContext(c.Request.Context()),
|
||||
Status: options.Status,
|
||||
ProviderCode: strings.TrimSpace(firstQuery(c, "provider_code", "providerCode")),
|
||||
Keyword: options.Keyword,
|
||||
Page: int32(options.Page),
|
||||
PageSize: int32(options.PageSize),
|
||||
})
|
||||
if err != nil {
|
||||
writeWalletError(c, err, "获取三方临时支付链接失败")
|
||||
return
|
||||
}
|
||||
items := make([]temporaryPaymentLinkDTO, 0, len(resp.GetOrders()))
|
||||
for _, item := range resp.GetOrders() {
|
||||
items = append(items, temporaryPaymentLinkFromProto(item))
|
||||
}
|
||||
response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: resp.GetTotal()})
|
||||
}
|
||||
|
||||
func (h *Handler) GetTemporaryPaymentLink(c *gin.Context) {
|
||||
orderID := strings.TrimSpace(c.Param("order_id"))
|
||||
if orderID == "" {
|
||||
response.BadRequest(c, "支付链接订单号不能为空")
|
||||
return
|
||||
}
|
||||
// 查询单条订单会进入 wallet-service 的支付状态刷新逻辑;admin 页面只发起核验,不在浏览器里拼三方查询参数。
|
||||
resp, err := h.wallet.GetTemporaryRechargeOrder(c.Request.Context(), &walletv1.GetTemporaryRechargeOrderRequest{
|
||||
RequestId: middleware.CurrentRequestID(c),
|
||||
AppCode: appctx.FromContext(c.Request.Context()),
|
||||
OrderId: orderID,
|
||||
})
|
||||
if err != nil {
|
||||
writeWalletError(c, err, "校验三方临时支付链接失败")
|
||||
return
|
||||
}
|
||||
response.OK(c, temporaryPaymentLinkFromProto(resp.GetOrder()))
|
||||
}
|
||||
|
||||
func (h *Handler) SetThirdPartyPaymentMethodStatus(c *gin.Context) {
|
||||
methodID := queryPathInt64(c, "method_id")
|
||||
if methodID <= 0 {
|
||||
|
||||
@ -90,6 +90,91 @@ func TestListThirdPartyPaymentChannelsForwardsIncludeDisabledMethods(t *testing.
|
||||
}
|
||||
}
|
||||
|
||||
func TestListTemporaryPaymentLinksForwardsFilters(t *testing.T) {
|
||||
wallet := &mockPaymentWallet{temporaryOrdersResp: &walletv1.ListTemporaryRechargeOrdersResponse{
|
||||
Total: 1,
|
||||
Orders: []*walletv1.ExternalRechargeOrder{{
|
||||
OrderId: "tmp_1001",
|
||||
AppCode: "lalu",
|
||||
AudienceType: "temporary",
|
||||
ProductName: "Temporary recharge 1000 coins",
|
||||
CoinAmount: 1000,
|
||||
UsdMinorAmount: 199,
|
||||
ProviderCode: "mifapay",
|
||||
PaymentMethodId: 810,
|
||||
CountryCode: "SA",
|
||||
CurrencyCode: "SAR",
|
||||
ProviderAmountMinor: 746,
|
||||
PayWay: "Card",
|
||||
PayType: "MADA",
|
||||
PayUrl: "https://pay.example/tmp_1001",
|
||||
ProviderOrderId: "mifa_1001",
|
||||
Status: "redirected",
|
||||
CreatedAtMs: 1700000000000,
|
||||
UpdatedAtMs: 1700000000001,
|
||||
}},
|
||||
}}
|
||||
router := newPaymentHandlerTestRouter(New(wallet, nil, nil))
|
||||
request := httptest.NewRequest(http.MethodGet, "/admin/payment/temporary-links?status=redirected&provider_code=mifapay&keyword=tmp&page=2&page_size=30", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if wallet.lastTemporaryOrders == nil ||
|
||||
wallet.lastTemporaryOrders.GetAppCode() != "lalu" ||
|
||||
wallet.lastTemporaryOrders.GetStatus() != "redirected" ||
|
||||
wallet.lastTemporaryOrders.GetProviderCode() != "mifapay" ||
|
||||
wallet.lastTemporaryOrders.GetKeyword() != "tmp" ||
|
||||
wallet.lastTemporaryOrders.GetPage() != 2 ||
|
||||
wallet.lastTemporaryOrders.GetPageSize() != 30 {
|
||||
t.Fatalf("temporary link list request mismatch: %+v", wallet.lastTemporaryOrders)
|
||||
}
|
||||
var response adminPaymentTestResponse
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
items := response.Data["items"].([]any)
|
||||
item := items[0].(map[string]any)
|
||||
if response.Code != 0 || response.Data["total"].(float64) != 1 || item["orderId"] != "tmp_1001" || item["payUrl"] != "https://pay.example/tmp_1001" || item["status"] != "redirected" {
|
||||
t.Fatalf("temporary link response mismatch: %+v", response)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetTemporaryPaymentLinkRefreshesSingleOrder(t *testing.T) {
|
||||
wallet := &mockPaymentWallet{temporaryOrderResp: &walletv1.H5RechargeOrderResponse{Order: &walletv1.ExternalRechargeOrder{
|
||||
OrderId: "tmp_1001",
|
||||
AppCode: "lalu",
|
||||
AudienceType: "temporary",
|
||||
ProviderCode: "v5pay",
|
||||
PayUrl: "https://pay.example/tmp_1001",
|
||||
Status: "paid",
|
||||
}}}
|
||||
router := newPaymentHandlerTestRouter(New(wallet, nil, nil))
|
||||
request := httptest.NewRequest(http.MethodGet, "/admin/payment/temporary-links/tmp_1001", nil)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
if wallet.lastTemporaryOrder == nil ||
|
||||
wallet.lastTemporaryOrder.GetAppCode() != "lalu" ||
|
||||
wallet.lastTemporaryOrder.GetOrderId() != "tmp_1001" {
|
||||
t.Fatalf("temporary link get request mismatch: %+v", wallet.lastTemporaryOrder)
|
||||
}
|
||||
var response adminPaymentTestResponse
|
||||
if err := json.NewDecoder(recorder.Body).Decode(&response); err != nil {
|
||||
t.Fatalf("decode response failed: %v", err)
|
||||
}
|
||||
if response.Code != 0 || response.Data["orderId"] != "tmp_1001" || response.Data["status"] != "paid" {
|
||||
t.Fatalf("temporary link get response mismatch: %+v", response)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetThirdPartyPaymentMethodStatusForwardsOperator(t *testing.T) {
|
||||
wallet := &mockPaymentWallet{}
|
||||
router := newPaymentHandlerTestRouter(New(wallet, nil, nil))
|
||||
@ -228,6 +313,8 @@ func newPaymentHandlerTestRouter(handler *Handler) *gin.Engine {
|
||||
c.Next()
|
||||
})
|
||||
router.GET("/admin/payment/third-party-channels", handler.ListThirdPartyPaymentChannels)
|
||||
router.GET("/admin/payment/temporary-links", handler.ListTemporaryPaymentLinks)
|
||||
router.GET("/admin/payment/temporary-links/:order_id", handler.GetTemporaryPaymentLink)
|
||||
router.PATCH("/admin/payment/third-party-methods/:method_id/status", handler.SetThirdPartyPaymentMethodStatus)
|
||||
router.PATCH("/admin/payment/third-party-rates/:method_id", handler.UpdateThirdPartyPaymentRate)
|
||||
router.POST("/admin/payment/third-party-rates/sync", handler.SyncThirdPartyPaymentRates)
|
||||
@ -245,6 +332,10 @@ type mockPaymentWallet struct {
|
||||
|
||||
lastThirdPartyChannels *walletv1.ListThirdPartyPaymentChannelsRequest
|
||||
thirdPartyChannelsResp *walletv1.ListThirdPartyPaymentChannelsResponse
|
||||
lastTemporaryOrders *walletv1.ListTemporaryRechargeOrdersRequest
|
||||
temporaryOrdersResp *walletv1.ListTemporaryRechargeOrdersResponse
|
||||
lastTemporaryOrder *walletv1.GetTemporaryRechargeOrderRequest
|
||||
temporaryOrderResp *walletv1.H5RechargeOrderResponse
|
||||
lastSetMethodStatus *walletv1.SetThirdPartyPaymentMethodStatusRequest
|
||||
lastUpdateRate *walletv1.UpdateThirdPartyPaymentRateRequest
|
||||
updateRateRequests []*walletv1.UpdateThirdPartyPaymentRateRequest
|
||||
@ -259,6 +350,22 @@ func (m *mockPaymentWallet) ListThirdPartyPaymentChannels(_ context.Context, req
|
||||
return &walletv1.ListThirdPartyPaymentChannelsResponse{}, nil
|
||||
}
|
||||
|
||||
func (m *mockPaymentWallet) ListTemporaryRechargeOrders(_ context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error) {
|
||||
m.lastTemporaryOrders = req
|
||||
if m.temporaryOrdersResp != nil {
|
||||
return m.temporaryOrdersResp, nil
|
||||
}
|
||||
return &walletv1.ListTemporaryRechargeOrdersResponse{}, nil
|
||||
}
|
||||
|
||||
func (m *mockPaymentWallet) GetTemporaryRechargeOrder(_ context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
m.lastTemporaryOrder = req
|
||||
if m.temporaryOrderResp != nil {
|
||||
return m.temporaryOrderResp, nil
|
||||
}
|
||||
return &walletv1.H5RechargeOrderResponse{Order: &walletv1.ExternalRechargeOrder{OrderId: req.GetOrderId(), Status: "pending"}}, nil
|
||||
}
|
||||
|
||||
func (m *mockPaymentWallet) SetThirdPartyPaymentMethodStatus(_ context.Context, req *walletv1.SetThirdPartyPaymentMethodStatusRequest) (*walletv1.ThirdPartyPaymentMethodResponse, error) {
|
||||
m.lastSetMethodStatus = req
|
||||
status := "disabled"
|
||||
|
||||
@ -13,6 +13,8 @@ func RegisterRoutes(protected *gin.RouterGroup, h *Handler) {
|
||||
|
||||
protected.GET("/admin/payment/recharge-bills", middleware.RequirePermission("payment-bill:view"), h.ListRechargeBills)
|
||||
protected.GET("/admin/payment/third-party-channels", middleware.RequirePermission("payment-third-party:view"), h.ListThirdPartyPaymentChannels)
|
||||
protected.GET("/admin/payment/temporary-links", middleware.RequirePermission("payment-temporary-link:view"), h.ListTemporaryPaymentLinks)
|
||||
protected.GET("/admin/payment/temporary-links/:order_id", middleware.RequirePermission("payment-temporary-link:view"), h.GetTemporaryPaymentLink)
|
||||
protected.PATCH("/admin/payment/third-party-methods/:method_id/status", middleware.RequirePermission("payment-third-party:update"), h.SetThirdPartyPaymentMethodStatus)
|
||||
protected.PATCH("/admin/payment/third-party-rates/:method_id", middleware.RequirePermission("payment-third-party:update"), h.UpdateThirdPartyPaymentRate)
|
||||
protected.POST("/admin/payment/third-party-rates/sync", middleware.RequirePermission("payment-third-party:update"), h.SyncThirdPartyPaymentRates)
|
||||
|
||||
61
server/admin/internal/modules/riskconfig/handler.go
Normal file
61
server/admin/internal/modules/riskconfig/handler.go
Normal file
@ -0,0 +1,61 @@
|
||||
package riskconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"hyapp-admin-server/internal/integration/userclient"
|
||||
"hyapp-admin-server/internal/middleware"
|
||||
"hyapp-admin-server/internal/modules/shared"
|
||||
"hyapp-admin-server/internal/response"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
user userclient.Client
|
||||
audit shared.OperationLogger
|
||||
}
|
||||
|
||||
func New(user userclient.Client, audit shared.OperationLogger) *Handler {
|
||||
return &Handler{user: user, audit: audit}
|
||||
}
|
||||
|
||||
type registerRiskConfigRequest struct {
|
||||
MaxAccountsPerDevice int32 `json:"max_accounts_per_device"`
|
||||
}
|
||||
|
||||
func (h *Handler) GetRegisterRiskConfig(c *gin.Context) {
|
||||
config, err := h.user.GetRegisterRiskConfig(c.Request.Context(), userclient.GetRegisterRiskConfigRequest{
|
||||
RequestID: middleware.CurrentRequestID(c),
|
||||
Caller: "admin-server",
|
||||
})
|
||||
if err != nil {
|
||||
response.ServerError(c, "获取风控配置失败")
|
||||
return
|
||||
}
|
||||
response.OK(c, config)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateRegisterRiskConfig(c *gin.Context) {
|
||||
var req registerRiskConfigRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
response.BadRequest(c, "风控配置参数不正确")
|
||||
return
|
||||
}
|
||||
if req.MaxAccountsPerDevice < 1 {
|
||||
response.BadRequest(c, "单设备最大账号数必须大于 0")
|
||||
return
|
||||
}
|
||||
config, err := h.user.UpdateRegisterRiskConfig(c.Request.Context(), userclient.UpdateRegisterRiskConfigRequest{
|
||||
RequestID: middleware.CurrentRequestID(c),
|
||||
Caller: "admin-server",
|
||||
MaxAccountsPerDevice: req.MaxAccountsPerDevice,
|
||||
OperatorAdminID: int64(middleware.CurrentUserID(c)),
|
||||
})
|
||||
if err != nil {
|
||||
response.BadRequest(c, err.Error())
|
||||
return
|
||||
}
|
||||
shared.OperationLog(c, h.audit, "update-risk-config", "auth_risk_configs", "success", fmt.Sprintf("max_accounts_per_device=%d", config.MaxAccountsPerDevice))
|
||||
response.OK(c, config)
|
||||
}
|
||||
16
server/admin/internal/modules/riskconfig/routes.go
Normal file
16
server/admin/internal/modules/riskconfig/routes.go
Normal file
@ -0,0 +1,16 @@
|
||||
package riskconfig
|
||||
|
||||
import (
|
||||
"hyapp-admin-server/internal/middleware"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func RegisterRoutes(protected *gin.RouterGroup, h *Handler) {
|
||||
if h == nil {
|
||||
return
|
||||
}
|
||||
|
||||
protected.GET("/admin/users/risk-config", middleware.RequirePermission("risk-config:view"), h.GetRegisterRiskConfig)
|
||||
protected.PUT("/admin/users/risk-config", middleware.RequirePermission("risk-config:update"), h.UpdateRegisterRiskConfig)
|
||||
}
|
||||
@ -26,6 +26,8 @@ var defaultPermissions = []model.Permission{
|
||||
{Name: "靓号池更新", Code: "pretty-id:update", Kind: "button"},
|
||||
{Name: "靓号批量生成", Code: "pretty-id:generate", Kind: "button"},
|
||||
{Name: "靓号后台发放", Code: "pretty-id:grant", Kind: "button"},
|
||||
{Name: "风控配置查看", Code: "risk-config:view", Kind: "menu"},
|
||||
{Name: "风控配置更新", Code: "risk-config:update", Kind: "button"},
|
||||
{Name: "地区屏蔽查看", Code: "region-block:view", Kind: "menu"},
|
||||
{Name: "地区屏蔽更新", Code: "region-block:update", Kind: "button"},
|
||||
{Name: "房间查看", Code: "room:view", Kind: "menu"},
|
||||
@ -109,6 +111,7 @@ var defaultPermissions = []model.Permission{
|
||||
{Name: "支付账单查看", Code: "payment-bill:view", Kind: "menu"},
|
||||
{Name: "三方支付查看", Code: "payment-third-party:view", Kind: "menu"},
|
||||
{Name: "三方支付更新", Code: "payment-third-party:update", Kind: "button"},
|
||||
{Name: "三方临时支付链接查看", Code: "payment-temporary-link:view", Kind: "menu"},
|
||||
{Name: "内购配置查看", Code: "payment-product:view", Kind: "menu"},
|
||||
{Name: "内购配置创建", Code: "payment-product:create", Kind: "button"},
|
||||
{Name: "内购配置更新", Code: "payment-product:update", Kind: "button"},
|
||||
@ -264,7 +267,8 @@ func (s *Store) seedMenus() error {
|
||||
{ParentID: &appUsersID, Title: "登录日志", Code: "app-user-login-logs", Path: "/app/users/login-logs", Icon: "login", PermissionCode: "app-user:view", Sort: 62, Visible: true},
|
||||
{ParentID: &appUsersID, Title: "等级配置", Code: "app-user-level-config", Path: "/app/users/level-config", Icon: "military_tech", PermissionCode: "level-config:view", Sort: 63, Visible: true},
|
||||
{ParentID: &appUsersID, Title: "靓号管理", Code: "app-user-pretty-ids", Path: "/app/users/pretty-ids", Icon: "tag", PermissionCode: "pretty-id:view", Sort: 64, Visible: true},
|
||||
{ParentID: &appUsersID, Title: "地区屏蔽", Code: "app-user-region-blocks", Path: "/app/users/region-blocks", Icon: "public", PermissionCode: "region-block:view", Sort: 65, Visible: true},
|
||||
{ParentID: &appUsersID, Title: "风控管理", Code: "app-user-risk-config", Path: "/app/users/risk-config", Icon: "shield", PermissionCode: "risk-config:view", Sort: 65, Visible: true},
|
||||
{ParentID: &appUsersID, Title: "地区屏蔽", Code: "app-user-region-blocks", Path: "/app/users/region-blocks", Icon: "public", PermissionCode: "region-block:view", Sort: 66, Visible: true},
|
||||
{ParentID: &roomsID, Title: "房间列表", Code: "room-list", Path: "/rooms", Icon: "room", PermissionCode: "room:view", Sort: 65, Visible: true},
|
||||
{ParentID: &roomsID, Title: "房间置顶", Code: "room-pins", Path: "/rooms/pins", Icon: "push_pin", PermissionCode: "room-pin:view", Sort: 66, Visible: true},
|
||||
{ParentID: &roomsID, Title: "房间配置", Code: "room-config", Path: "/rooms/config", Icon: "settings", PermissionCode: "room-config:view", Sort: 67, Visible: true},
|
||||
@ -291,7 +295,8 @@ func (s *Store) seedMenus() error {
|
||||
{ParentID: &operationsID, Title: "全服通知", Code: "operation-full-server-notice", Path: "/operations/full-server-notices", Icon: "campaign", PermissionCode: "full-server-notice:view", Sort: 75, Visible: true},
|
||||
{ParentID: &paymentID, Title: "账单列表", Code: "payment-bill-list", Path: "/payment/bills", Icon: "receipt", PermissionCode: "payment-bill:view", Sort: 68, Visible: true},
|
||||
{ParentID: &paymentID, Title: "三方支付", Code: "payment-third-party", Path: "/payment/third-party", Icon: "wallet", PermissionCode: "payment-third-party:view", Sort: 69, Visible: true},
|
||||
{ParentID: &paymentID, Title: "支付内购商品", Code: "payment-recharge-products", Path: "/payment/recharge-products", Icon: "wallet", PermissionCode: "payment-product:view", Sort: 70, Visible: true},
|
||||
{ParentID: &paymentID, Title: "三方临时支付链接", Code: "payment-temporary-links", Path: "/payment/temporary-links", Icon: "receipt", PermissionCode: "payment-temporary-link:view", Sort: 70, Visible: true},
|
||||
{ParentID: &paymentID, Title: "支付内购商品", Code: "payment-recharge-products", Path: "/payment/recharge-products", Icon: "wallet", PermissionCode: "payment-product:view", Sort: 71, Visible: true},
|
||||
{ParentID: &activityID, Title: "每日任务", Code: "daily-task-list", Path: "/activities/daily-tasks", Icon: "task", PermissionCode: "daily-task:view", Sort: 69, Visible: true},
|
||||
{ParentID: &activityID, Title: "注册奖励", Code: "registration-reward", Path: "/activities/registration-reward", Icon: "gift", PermissionCode: "registration-reward:view", Sort: 70, Visible: true},
|
||||
{ParentID: &activityID, Title: "成就配置", Code: "achievement-config", Path: "/activities/achievements", Icon: "military_tech", PermissionCode: "achievement:view", Sort: 71, Visible: true},
|
||||
@ -528,6 +533,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"app-user:view", "app-user:update", "app-user:status", "app-user:password",
|
||||
"level-config:view", "level-config:update",
|
||||
"pretty-id:view", "pretty-id:update", "pretty-id:generate", "pretty-id:grant",
|
||||
"risk-config:view", "risk-config:update",
|
||||
"region-block:view", "region-block:update",
|
||||
"room:view", "room:update", "room:delete", "room-pin:view", "room-pin:create", "room-pin:cancel", "room-config:view", "room-config:update", "room-whitelist:view", "room-whitelist:update", "room-robot:view", "room-robot:create", "room-robot:update",
|
||||
"app-config:view", "app-config:update",
|
||||
@ -544,7 +550,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"agency:view", "agency:create", "agency:status", "agency:delete",
|
||||
"bd:view", "bd:create", "bd:update",
|
||||
"coin-seller:view", "coin-seller:create", "coin-seller:update", "coin-seller:stock-credit", "coin-seller:exchange-rate",
|
||||
"coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "coin-adjustment:create", "report:view", "gift-diamond:view", "gift-diamond:update", "full-server-notice:view", "full-server-notice:send", "payment-bill:view", "payment-third-party:view", "payment-third-party:update", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete",
|
||||
"coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "coin-adjustment:create", "report:view", "gift-diamond:view", "gift-diamond:update", "full-server-notice:view", "full-server-notice:send", "payment-bill:view", "payment-third-party:view", "payment-third-party:update", "payment-temporary-link:view", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete",
|
||||
"lucky-gift:view", "lucky-gift:update", "wheel:view", "wheel:update",
|
||||
"game:view", "game:create", "game:update", "game:status", "game:delete",
|
||||
"daily-task:view", "daily-task:create", "daily-task:update", "daily-task:status",
|
||||
@ -561,7 +567,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"upload:create",
|
||||
}
|
||||
case "auditor":
|
||||
return []string{"overview:view", "log:view", "user:view", "app-user:view", "level-config:view", "pretty-id:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-whitelist:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "wheel:view", "payment-bill:view", "payment-third-party:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view", "role:view", "permission:view", "job:view"}
|
||||
return []string{"overview:view", "log:view", "user:view", "app-user:view", "level-config:view", "pretty-id:view", "risk-config:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-whitelist:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "wheel:view", "payment-bill:view", "payment-third-party:view", "payment-temporary-link:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view", "role:view", "permission:view", "job:view"}
|
||||
case "readonly":
|
||||
return []string{
|
||||
"overview:view",
|
||||
@ -569,6 +575,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"app-user:view",
|
||||
"level-config:view",
|
||||
"pretty-id:view",
|
||||
"risk-config:view",
|
||||
"region-block:view",
|
||||
"room:view",
|
||||
"room-pin:view",
|
||||
@ -602,6 +609,7 @@ func defaultRolePermissionCodes(code string) []string {
|
||||
"wheel:view",
|
||||
"payment-bill:view",
|
||||
"payment-third-party:view",
|
||||
"payment-temporary-link:view",
|
||||
"payment-product:view",
|
||||
"game:view",
|
||||
"daily-task:view",
|
||||
@ -634,6 +642,7 @@ func defaultRolePermissionMigrationCodes(code string) []string {
|
||||
"app-version:view", "app-version:create", "app-version:update", "app-version:delete",
|
||||
"level-config:view", "level-config:update",
|
||||
"pretty-id:view", "pretty-id:update", "pretty-id:generate", "pretty-id:grant",
|
||||
"risk-config:view", "risk-config:update",
|
||||
"region-block:view", "region-block:update",
|
||||
"resource:view", "resource:create", "resource:update",
|
||||
"resource-shop:view", "resource-shop:update",
|
||||
@ -646,7 +655,7 @@ func defaultRolePermissionMigrationCodes(code string) []string {
|
||||
"region:view", "region:create", "region:update", "region:status",
|
||||
"host-agency-policy:view", "host-agency-policy:create", "host-agency-policy:update", "host-agency-policy:delete", "host-agency-policy:publish", "team-salary-policy:view", "team-salary-policy:create", "team-salary-policy:update", "team-salary-policy:delete", "host-salary-settlement:view", "host-salary-settlement:settle",
|
||||
"coin-seller:view", "coin-seller:create", "coin-seller:update", "coin-seller:stock-credit", "coin-seller:exchange-rate",
|
||||
"coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "coin-adjustment:create", "report:view", "gift-diamond:view", "gift-diamond:update", "full-server-notice:view", "full-server-notice:send", "payment-bill:view", "payment-third-party:view", "payment-third-party:update", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete",
|
||||
"coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "coin-adjustment:create", "report:view", "gift-diamond:view", "gift-diamond:update", "full-server-notice:view", "full-server-notice:send", "payment-bill:view", "payment-third-party:view", "payment-third-party:update", "payment-temporary-link:view", "payment-product:view", "payment-product:create", "payment-product:update", "payment-product:delete",
|
||||
"lucky-gift:view", "lucky-gift:update", "wheel:view", "wheel:update",
|
||||
"game:view", "game:create", "game:update", "game:status", "game:delete",
|
||||
"daily-task:view", "daily-task:create", "daily-task:update", "daily-task:status",
|
||||
@ -660,7 +669,7 @@ func defaultRolePermissionMigrationCodes(code string) []string {
|
||||
"agency-opening:view", "agency-opening:create", "agency-opening:update",
|
||||
}
|
||||
case "auditor", "readonly":
|
||||
return []string{"level-config:view", "pretty-id:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-whitelist:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-seller:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "wheel:view", "payment-bill:view", "payment-third-party:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view"}
|
||||
return []string{"level-config:view", "pretty-id:view", "risk-config:view", "region-block:view", "room:view", "room-pin:view", "room-config:view", "room-whitelist:view", "room-robot:view", "app-config:view", "app-version:view", "resource:view", "resource-shop:view", "resource-group:view", "resource-grant:view", "gift:view", "emoji-pack:view", "host-agency-policy:view", "team-salary-policy:view", "host-salary-settlement:view", "coin-seller:view", "coin-ledger:view", "coin-seller-ledger:view", "coin-adjustment:view", "report:view", "gift-diamond:view", "full-server-notice:view", "lucky-gift:view", "wheel:view", "payment-bill:view", "payment-third-party:view", "payment-temporary-link:view", "payment-product:view", "game:view", "daily-task:view", "achievement:view", "seven-day-checkin:view", "room-rocket:view", "red-packet:view", "cp-config:view", "vip-config:view", "weekly-star:view", "agency-opening:view"}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ import (
|
||||
"hyapp-admin-server/internal/modules/registrationreward"
|
||||
reportmodule "hyapp-admin-server/internal/modules/report"
|
||||
resourcemodule "hyapp-admin-server/internal/modules/resource"
|
||||
"hyapp-admin-server/internal/modules/riskconfig"
|
||||
"hyapp-admin-server/internal/modules/roomadmin"
|
||||
"hyapp-admin-server/internal/modules/roomrocket"
|
||||
"hyapp-admin-server/internal/modules/roomturnoverreward"
|
||||
@ -92,6 +93,7 @@ type Handlers struct {
|
||||
RegistrationReward *registrationreward.Handler
|
||||
RegionBlock *regionblock.Handler
|
||||
Resource *resourcemodule.Handler
|
||||
RiskConfig *riskconfig.Handler
|
||||
RoomAdmin *roomadmin.Handler
|
||||
RoomRocket *roomrocket.Handler
|
||||
RoomTurnoverReward *roomturnoverreward.Handler
|
||||
@ -138,6 +140,7 @@ func New(cfg config.Config, auth *service.AuthService, h Handlers) *gin.Engine {
|
||||
fullservernotice.RegisterRoutes(protected, h.FullServerNotice)
|
||||
registrationreward.RegisterRoutes(protected, h.RegistrationReward)
|
||||
regionblock.RegisterRoutes(protected, h.RegionBlock)
|
||||
riskconfig.RegisterRoutes(protected, h.RiskConfig)
|
||||
gamemanagement.RegisterRoutes(protected, h.Game)
|
||||
giftdiamond.RegisterRoutes(protected, h.GiftDiamond)
|
||||
roomadmin.RegisterRoutes(protected, h.RoomAdmin)
|
||||
|
||||
46
server/admin/migrations/060_risk_config_navigation.sql
Normal file
46
server/admin/migrations/060_risk_config_navigation.sql
Normal file
@ -0,0 +1,46 @@
|
||||
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 注册风控配置由 user-service 执行,后台只负责维护菜单、权限和跨服务配置入口。
|
||||
SET @now_ms = CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED);
|
||||
|
||||
INSERT INTO admin_permissions (name, code, kind, description, created_at_ms, updated_at_ms) VALUES
|
||||
('风控配置查看', 'risk-config:view', 'menu', '', @now_ms, @now_ms),
|
||||
('风控配置更新', 'risk-config:update', 'button', '', @now_ms, @now_ms)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
kind = VALUES(kind),
|
||||
description = VALUES(description),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
INSERT INTO admin_menus (parent_id, title, code, path, icon, permission_code, sort, visible, created_at_ms, updated_at_ms)
|
||||
SELECT parent.id, '风控管理', 'app-user-risk-config', '/app/users/risk-config', 'shield', 'risk-config:view', 65, TRUE, @now_ms, @now_ms
|
||||
FROM admin_menus parent
|
||||
WHERE parent.code = 'app-users'
|
||||
ON DUPLICATE KEY UPDATE
|
||||
parent_id = VALUES(parent_id),
|
||||
title = VALUES(title),
|
||||
path = VALUES(path),
|
||||
icon = VALUES(icon),
|
||||
permission_code = VALUES(permission_code),
|
||||
sort = VALUES(sort),
|
||||
visible = VALUES(visible),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
UPDATE admin_menus
|
||||
SET sort = 66, updated_at_ms = @now_ms
|
||||
WHERE code = 'app-user-region-blocks'
|
||||
AND sort < 66;
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
|
||||
SELECT admin_role.id, admin_permission.id
|
||||
FROM admin_roles admin_role
|
||||
JOIN admin_permissions admin_permission
|
||||
WHERE admin_role.code IN ('platform-admin', 'ops-admin')
|
||||
AND admin_permission.code IN ('risk-config:view', 'risk-config:update');
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
|
||||
SELECT admin_role.id, admin_permission.id
|
||||
FROM admin_roles admin_role
|
||||
JOIN admin_permissions admin_permission
|
||||
WHERE admin_role.code IN ('auditor', 'readonly')
|
||||
AND admin_permission.code = 'risk-config:view';
|
||||
@ -0,0 +1,37 @@
|
||||
SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- 三方临时支付链接只用于内部追踪临时支付订单;权限独立于三方支付配置更新权限,避免只读运营误改渠道配置。
|
||||
SET @now_ms = CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED);
|
||||
|
||||
INSERT INTO admin_permissions (name, code, kind, description, created_at_ms, updated_at_ms) VALUES
|
||||
('三方临时支付链接查看', 'payment-temporary-link:view', 'menu', '', @now_ms, @now_ms)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
name = VALUES(name),
|
||||
kind = VALUES(kind),
|
||||
description = VALUES(description),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
INSERT INTO admin_menus (parent_id, title, code, path, icon, permission_code, sort, visible, created_at_ms, updated_at_ms)
|
||||
SELECT parent.id, '三方临时支付链接', 'payment-temporary-links', '/payment/temporary-links', 'receipt', 'payment-temporary-link:view', 70, TRUE, @now_ms, @now_ms
|
||||
FROM admin_menus parent
|
||||
WHERE parent.code = 'payment'
|
||||
ON DUPLICATE KEY UPDATE
|
||||
parent_id = VALUES(parent_id),
|
||||
title = VALUES(title),
|
||||
path = VALUES(path),
|
||||
icon = VALUES(icon),
|
||||
permission_code = VALUES(permission_code),
|
||||
sort = VALUES(sort),
|
||||
visible = VALUES(visible),
|
||||
updated_at_ms = @now_ms;
|
||||
|
||||
UPDATE admin_menus
|
||||
SET sort = 71, updated_at_ms = @now_ms
|
||||
WHERE code = 'payment-recharge-products';
|
||||
|
||||
INSERT IGNORE INTO admin_role_permissions (role_id, permission_id)
|
||||
SELECT admin_role.id, admin_permission.id
|
||||
FROM admin_roles admin_role
|
||||
JOIN admin_permissions admin_permission
|
||||
WHERE admin_role.code IN ('platform-admin', 'ops-admin', 'auditor', 'readonly')
|
||||
AND admin_permission.code = 'payment-temporary-link:view';
|
||||
@ -17,8 +17,12 @@ type WalletClient interface {
|
||||
GetWalletValueSummary(ctx context.Context, req *walletv1.GetWalletValueSummaryRequest) (*walletv1.GetWalletValueSummaryResponse, error)
|
||||
GetUserGiftWall(ctx context.Context, req *walletv1.GetUserGiftWallRequest) (*walletv1.GetUserGiftWallResponse, error)
|
||||
ListRechargeProducts(ctx context.Context, req *walletv1.ListRechargeProductsRequest) (*walletv1.ListRechargeProductsResponse, error)
|
||||
ListThirdPartyPaymentChannels(ctx context.Context, req *walletv1.ListThirdPartyPaymentChannelsRequest) (*walletv1.ListThirdPartyPaymentChannelsResponse, error)
|
||||
ListH5RechargeOptions(ctx context.Context, req *walletv1.H5RechargeOptionsRequest) (*walletv1.H5RechargeOptionsResponse, error)
|
||||
CreateH5RechargeOrder(ctx context.Context, req *walletv1.CreateH5RechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error)
|
||||
CreateTemporaryRechargeOrder(ctx context.Context, req *walletv1.CreateTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error)
|
||||
GetTemporaryRechargeOrder(ctx context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error)
|
||||
ListTemporaryRechargeOrders(ctx context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error)
|
||||
SubmitH5RechargeTx(ctx context.Context, req *walletv1.SubmitH5RechargeTxRequest) (*walletv1.H5RechargeOrderResponse, error)
|
||||
GetH5RechargeOrder(ctx context.Context, req *walletv1.GetH5RechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error)
|
||||
HandleMifapayNotify(ctx context.Context, req *walletv1.HandleMifapayNotifyRequest) (*walletv1.HandleMifapayNotifyResponse, error)
|
||||
@ -92,6 +96,10 @@ func (c *grpcWalletClient) ListRechargeProducts(ctx context.Context, req *wallet
|
||||
return c.client.ListRechargeProducts(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) ListThirdPartyPaymentChannels(ctx context.Context, req *walletv1.ListThirdPartyPaymentChannelsRequest) (*walletv1.ListThirdPartyPaymentChannelsResponse, error) {
|
||||
return c.client.ListThirdPartyPaymentChannels(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) ListH5RechargeOptions(ctx context.Context, req *walletv1.H5RechargeOptionsRequest) (*walletv1.H5RechargeOptionsResponse, error) {
|
||||
return c.client.ListH5RechargeOptions(ctx, req)
|
||||
}
|
||||
@ -100,6 +108,18 @@ func (c *grpcWalletClient) CreateH5RechargeOrder(ctx context.Context, req *walle
|
||||
return c.client.CreateH5RechargeOrder(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) CreateTemporaryRechargeOrder(ctx context.Context, req *walletv1.CreateTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
return c.client.CreateTemporaryRechargeOrder(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) GetTemporaryRechargeOrder(ctx context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
return c.client.GetTemporaryRechargeOrder(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) ListTemporaryRechargeOrders(ctx context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error) {
|
||||
return c.client.ListTemporaryRechargeOrders(ctx, req)
|
||||
}
|
||||
|
||||
func (c *grpcWalletClient) SubmitH5RechargeTx(ctx context.Context, req *walletv1.SubmitH5RechargeTxRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
return c.client.SubmitH5RechargeTx(ctx, req)
|
||||
}
|
||||
|
||||
@ -232,6 +232,10 @@ type WalletHandlers struct {
|
||||
GetH5RechargeContext http.HandlerFunc
|
||||
ListH5RechargeOptions http.HandlerFunc
|
||||
CreateH5RechargeOrder http.HandlerFunc
|
||||
ListTemporaryPayMethods http.HandlerFunc
|
||||
CreateTemporaryPayLink http.HandlerFunc
|
||||
GetTemporaryPayLink http.HandlerFunc
|
||||
ListTemporaryPayLinks http.HandlerFunc
|
||||
SubmitH5RechargeTx http.HandlerFunc
|
||||
GetH5RechargeOrder http.HandlerFunc
|
||||
HandleMifapayNotify http.HandlerFunc
|
||||
@ -567,6 +571,10 @@ func (r routes) registerWalletRoutes() {
|
||||
r.public("/recharge/h5/context", http.MethodGet, h.GetH5RechargeContext)
|
||||
r.public("/recharge/h5/options", http.MethodGet, h.ListH5RechargeOptions)
|
||||
r.public("/recharge/h5/orders", http.MethodPost, h.CreateH5RechargeOrder)
|
||||
r.public("/recharge/h5/temporary/methods", http.MethodGet, h.ListTemporaryPayMethods)
|
||||
r.public("/recharge/h5/temporary/orders", http.MethodPost, h.CreateTemporaryPayLink)
|
||||
r.public("/recharge/h5/temporary/order-list", http.MethodGet, h.ListTemporaryPayLinks)
|
||||
r.public("/recharge/h5/temporary/orders/{order_id}", http.MethodGet, h.GetTemporaryPayLink)
|
||||
r.public("/recharge/h5/orders/{order_id}/tx", http.MethodPost, h.SubmitH5RechargeTx)
|
||||
r.public("/recharge/h5/orders/{order_id}", http.MethodGet, h.GetH5RechargeOrder)
|
||||
r.public("/payment/mifapay/notify", http.MethodPost, h.HandleMifapayNotify)
|
||||
|
||||
@ -502,10 +502,18 @@ type fakeWalletClient struct {
|
||||
giftWallResp *walletv1.GetUserGiftWallResponse
|
||||
lastRechargeProducts *walletv1.ListRechargeProductsRequest
|
||||
rechargeProductsResp *walletv1.ListRechargeProductsResponse
|
||||
lastThirdPartyChannels *walletv1.ListThirdPartyPaymentChannelsRequest
|
||||
thirdPartyChannelsResp *walletv1.ListThirdPartyPaymentChannelsResponse
|
||||
lastH5Options *walletv1.H5RechargeOptionsRequest
|
||||
h5OptionsResp *walletv1.H5RechargeOptionsResponse
|
||||
lastH5CreateOrder *walletv1.CreateH5RechargeOrderRequest
|
||||
h5CreateOrderResp *walletv1.H5RechargeOrderResponse
|
||||
lastTemporaryCreate *walletv1.CreateTemporaryRechargeOrderRequest
|
||||
temporaryCreateResp *walletv1.H5RechargeOrderResponse
|
||||
lastTemporaryGet *walletv1.GetTemporaryRechargeOrderRequest
|
||||
temporaryGetResp *walletv1.H5RechargeOrderResponse
|
||||
lastTemporaryList *walletv1.ListTemporaryRechargeOrdersRequest
|
||||
temporaryListResp *walletv1.ListTemporaryRechargeOrdersResponse
|
||||
lastH5SubmitTx *walletv1.SubmitH5RechargeTxRequest
|
||||
h5SubmitTxResp *walletv1.H5RechargeOrderResponse
|
||||
lastH5GetOrder *walletv1.GetH5RechargeOrderRequest
|
||||
@ -1678,6 +1686,17 @@ func (f *fakeWalletClient) ListRechargeProducts(_ context.Context, req *walletv1
|
||||
return &walletv1.ListRechargeProductsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) ListThirdPartyPaymentChannels(_ context.Context, req *walletv1.ListThirdPartyPaymentChannelsRequest) (*walletv1.ListThirdPartyPaymentChannelsResponse, error) {
|
||||
f.lastThirdPartyChannels = req
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
if f.thirdPartyChannelsResp != nil {
|
||||
return f.thirdPartyChannelsResp, nil
|
||||
}
|
||||
return &walletv1.ListThirdPartyPaymentChannelsResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) ListH5RechargeOptions(_ context.Context, req *walletv1.H5RechargeOptionsRequest) (*walletv1.H5RechargeOptionsResponse, error) {
|
||||
f.lastH5Options = req
|
||||
if f.err != nil {
|
||||
@ -1700,6 +1719,39 @@ func (f *fakeWalletClient) CreateH5RechargeOrder(_ context.Context, req *walletv
|
||||
return &walletv1.H5RechargeOrderResponse{Order: &walletv1.ExternalRechargeOrder{OrderId: "h5-order-1", Status: "pending"}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) CreateTemporaryRechargeOrder(_ context.Context, req *walletv1.CreateTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
f.lastTemporaryCreate = req
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
if f.temporaryCreateResp != nil {
|
||||
return f.temporaryCreateResp, nil
|
||||
}
|
||||
return &walletv1.H5RechargeOrderResponse{Order: &walletv1.ExternalRechargeOrder{OrderId: "temporary-order-1", Status: "pending"}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) GetTemporaryRechargeOrder(_ context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
f.lastTemporaryGet = req
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
if f.temporaryGetResp != nil {
|
||||
return f.temporaryGetResp, nil
|
||||
}
|
||||
return &walletv1.H5RechargeOrderResponse{Order: &walletv1.ExternalRechargeOrder{OrderId: req.GetOrderId(), Status: "pending"}}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) ListTemporaryRechargeOrders(_ context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error) {
|
||||
f.lastTemporaryList = req
|
||||
if f.err != nil {
|
||||
return nil, f.err
|
||||
}
|
||||
if f.temporaryListResp != nil {
|
||||
return f.temporaryListResp, nil
|
||||
}
|
||||
return &walletv1.ListTemporaryRechargeOrdersResponse{}, nil
|
||||
}
|
||||
|
||||
func (f *fakeWalletClient) SubmitH5RechargeTx(_ context.Context, req *walletv1.SubmitH5RechargeTxRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
f.lastH5SubmitTx = req
|
||||
if f.err != nil {
|
||||
@ -2499,6 +2551,48 @@ func TestSendGiftForwardsMultipleTargetUserIDs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendGiftInjectsDisplayProfilesForIMSnapshot(t *testing.T) {
|
||||
roomClient := &fakeRoomClient{}
|
||||
profileClient := &fakeUserProfileClient{usersByID: map[int64]*userv1.User{
|
||||
42: {
|
||||
UserId: 42,
|
||||
DisplayUserId: "100042",
|
||||
PrettyDisplayUserId: "888042",
|
||||
Username: "Robot Sender",
|
||||
Avatar: "https://cdn.example/sender.png",
|
||||
CountryId: 840,
|
||||
RegionId: 1001,
|
||||
},
|
||||
43: {
|
||||
UserId: 43,
|
||||
DisplayUserId: "100043",
|
||||
PrettyDisplayUserId: "888043",
|
||||
Username: "Robot Receiver",
|
||||
Avatar: "https://cdn.example/receiver.png",
|
||||
CountryId: 840,
|
||||
RegionId: 1001,
|
||||
},
|
||||
}}
|
||||
router := NewHandlerWithClients(roomClient, nil, nil, profileClient).Routes(auth.NewVerifier("secret"))
|
||||
request := httptest.NewRequest(http.MethodPost, "/api/v1/rooms/gift/send", bytes.NewReader([]byte(`{"room_id":"room-1","command_id":"cmd-gift-profile","target_user_id":43,"gift_id":"rose","gift_count":1}`)))
|
||||
request.Header.Set("Authorization", "Bearer "+signGatewayToken(t, "secret", 42))
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
router.ServeHTTP(recorder, request)
|
||||
|
||||
if recorder.Code != http.StatusOK {
|
||||
t.Fatalf("status mismatch: got %d body=%s", recorder.Code, recorder.Body.String())
|
||||
}
|
||||
sender := roomClient.lastGift.GetSenderDisplayProfile()
|
||||
if sender.GetUserId() != 42 || sender.GetUsername() != "Robot Sender" || sender.GetAvatar() == "" || sender.GetDisplayUserId() != "100042" || sender.GetPrettyDisplayUserId() != "888042" {
|
||||
t.Fatalf("gateway must inject sender display profile snapshot: %+v", sender)
|
||||
}
|
||||
targets := roomClient.lastGift.GetTargetDisplayProfiles()
|
||||
if len(targets) != 1 || targets[0].GetUserId() != 43 || targets[0].GetUsername() != "Robot Receiver" || targets[0].GetAvatar() == "" || targets[0].GetDisplayUserId() != "100043" {
|
||||
t.Fatalf("gateway must inject target display profile snapshots: %+v", targets)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendGiftInjectsHostPeriodScopeForEachTarget(t *testing.T) {
|
||||
roomClient := &fakeRoomClient{}
|
||||
hostClient := &fakeUserHostClient{hostProfiles: map[int64]*userv1.HostProfile{
|
||||
|
||||
@ -31,6 +31,10 @@ const (
|
||||
roomAppearanceResourceVehicle = "vehicle"
|
||||
roomAppearanceResourceBadge = "badge"
|
||||
roomAppearanceResourceMicSeatAnimation = "mic_seat_animation"
|
||||
|
||||
// 机器人房标记来自 room-service RoomExt;gateway 只用它决定首屏资料是否补机器人头像昵称。
|
||||
roomExtRobotRoomKey = "robot_room"
|
||||
roomExtRobotUserIDsKey = "robot_user_ids"
|
||||
)
|
||||
|
||||
type flexibleInt64 int64
|
||||
@ -1564,6 +1568,7 @@ func (h *Handler) sendGift(writer http.ResponseWriter, request *http.Request) {
|
||||
return
|
||||
}
|
||||
firstTargetScope := firstGiftTargetHostScope(targetHostScopes, firstUserID(targetUserIDs))
|
||||
senderDisplayProfile, targetDisplayProfiles := h.resolveGiftDisplayProfiles(request, targetUserIDs)
|
||||
|
||||
resp, err := h.roomClient.SendGift(request.Context(), &roomv1.SendGiftRequest{
|
||||
Meta: httpkit.RoomMeta(request, body.RoomID, body.CommandID),
|
||||
@ -1581,6 +1586,8 @@ func (h *Handler) sendGift(writer http.ResponseWriter, request *http.Request) {
|
||||
TargetHostScopes: targetHostScopes,
|
||||
EntitlementId: strings.TrimSpace(body.EntitlementID),
|
||||
Source: strings.TrimSpace(body.Source),
|
||||
SenderDisplayProfile: senderDisplayProfile,
|
||||
TargetDisplayProfiles: targetDisplayProfiles,
|
||||
})
|
||||
httpkit.Write(writer, request, resp, err)
|
||||
}
|
||||
@ -1647,6 +1654,47 @@ func (h *Handler) resolveGiftTargetHostScopes(request *http.Request, targetUserI
|
||||
return scopes, nil
|
||||
}
|
||||
|
||||
func (h *Handler) resolveGiftDisplayProfiles(request *http.Request, targetUserIDs []int64) (*roomv1.SendGiftDisplayProfile, []*roomv1.SendGiftDisplayProfile) {
|
||||
if h.userProfileClient == nil {
|
||||
return nil, nil
|
||||
}
|
||||
senderUserID := auth.UserIDFromContext(request.Context())
|
||||
userIDs := uniquePositiveUserIDs(append([]int64{senderUserID}, targetUserIDs...))
|
||||
if len(userIDs) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
resp, err := h.userProfileClient.BatchGetUsers(request.Context(), &userv1.BatchGetUsersRequest{
|
||||
Meta: httpkit.UserMeta(request, ""),
|
||||
UserIds: userIDs,
|
||||
})
|
||||
if err != nil {
|
||||
// 展示快照只影响 IM 昵称头像兜底,不能因为增强资料读取失败阻断已经通过国家/主播校验的送礼主链路。
|
||||
return nil, nil
|
||||
}
|
||||
sender := giftDisplayProfileFromUser(resp.GetUsers()[senderUserID])
|
||||
targets := make([]*roomv1.SendGiftDisplayProfile, 0, len(targetUserIDs))
|
||||
for _, targetUserID := range targetUserIDs {
|
||||
if profile := giftDisplayProfileFromUser(resp.GetUsers()[targetUserID]); profile != nil {
|
||||
targets = append(targets, profile)
|
||||
}
|
||||
}
|
||||
return sender, targets
|
||||
}
|
||||
|
||||
func giftDisplayProfileFromUser(user *userv1.User) *roomv1.SendGiftDisplayProfile {
|
||||
if user == nil || user.GetUserId() <= 0 {
|
||||
return nil
|
||||
}
|
||||
// 这里不生成 User<ID> 兜底;客户端已有最终兜底,后端只传真实用户资料快照。
|
||||
return &roomv1.SendGiftDisplayProfile{
|
||||
UserId: user.GetUserId(),
|
||||
Username: strings.TrimSpace(user.GetUsername()),
|
||||
Avatar: strings.TrimSpace(user.GetAvatar()),
|
||||
DisplayUserId: strings.TrimSpace(user.GetDisplayUserId()),
|
||||
PrettyDisplayUserId: strings.TrimSpace(user.GetPrettyDisplayUserId()),
|
||||
}
|
||||
}
|
||||
|
||||
func firstGiftTargetHostScope(scopes []*roomv1.SendGiftTargetHostScope, targetUserID int64) *roomv1.SendGiftTargetHostScope {
|
||||
for _, scope := range scopes {
|
||||
if scope.GetTargetUserId() == targetUserID {
|
||||
@ -2399,3 +2447,26 @@ func firstUserID(userIDs []int64) int64 {
|
||||
}
|
||||
return userIDs[0]
|
||||
}
|
||||
|
||||
func robotRoomProfileUserIDs(snapshot *roomv1.RoomSnapshot) []int64 {
|
||||
if snapshot == nil || snapshot.GetRoomExt()[roomExtRobotRoomKey] != "true" {
|
||||
return nil
|
||||
}
|
||||
return parsePositiveInt64CSV(snapshot.GetRoomExt()[roomExtRobotUserIDsKey])
|
||||
}
|
||||
|
||||
func parsePositiveInt64CSV(raw string) []int64 {
|
||||
userIDs := make([]int64, 0)
|
||||
for piece := range strings.SplitSeq(raw, ",") {
|
||||
piece = strings.TrimSpace(piece)
|
||||
if piece == "" {
|
||||
continue
|
||||
}
|
||||
userID, err := strconv.ParseInt(piece, 10, 64)
|
||||
if err != nil || userID <= 0 {
|
||||
continue
|
||||
}
|
||||
userIDs = append(userIDs, userID)
|
||||
}
|
||||
return uniquePositiveUserIDs(userIDs)
|
||||
}
|
||||
|
||||
@ -241,6 +241,29 @@ func TestRoomProfileCountryFlag(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoomInitialProfileUserIDsIncludesRobotRoomUsers(t *testing.T) {
|
||||
snapshot := &roomv1.RoomSnapshot{
|
||||
OwnerUserId: 101,
|
||||
MicSeats: []*roomv1.SeatState{{UserId: 102}},
|
||||
GiftRank: []*roomv1.RankItem{{UserId: 201}},
|
||||
RoomExt: map[string]string{
|
||||
roomExtRobotRoomKey: "true",
|
||||
roomExtRobotUserIDsKey: "301,302,101,bad,0",
|
||||
},
|
||||
}
|
||||
|
||||
got := roomInitialProfileUserIDs(snapshot, 42, 10)
|
||||
want := []int64{101, 42, 102, 201, 301, 302}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("profile user id length mismatch: got=%v want=%v", got, want)
|
||||
}
|
||||
for index := range want {
|
||||
if got[index] != want[index] {
|
||||
t.Fatalf("profile user ids mismatch: got=%v want=%v", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type shareRoomQueryClient struct {
|
||||
lastSnapshot *roomv1.GetRoomSnapshotRequest
|
||||
snapshotResp *roomv1.GetRoomSnapshotResponse
|
||||
|
||||
@ -960,6 +960,10 @@ func roomInitialProfileUserIDs(snapshot *roomv1.RoomSnapshot, viewerUserID int64
|
||||
for _, item := range rank {
|
||||
add(item.GetUserId())
|
||||
}
|
||||
for _, userID := range robotRoomProfileUserIDs(snapshot) {
|
||||
// 机器人房间的礼物时间线会马上用机器人 sender/target 资料;首屏带出这些 profile,避免 Flutter 落到 User <id> 兜底。
|
||||
add(userID)
|
||||
}
|
||||
return userIDs
|
||||
}
|
||||
|
||||
|
||||
@ -52,6 +52,7 @@ func (h *Handler) Routes(jwtVerifier *auth.Verifier) http.Handler {
|
||||
UserProfileClient: h.userProfileClient,
|
||||
UserHostClient: h.userHostClient,
|
||||
IMGroupIDPrefix: h.tencentIM.GroupIDPrefix,
|
||||
ObjectUploader: h.objectUploader,
|
||||
})
|
||||
userAPI := userapi.New(userapi.Config{
|
||||
UserIdentityClient: h.userIdentityClient,
|
||||
|
||||
@ -1,12 +1,15 @@
|
||||
package walletapi
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
userv1 "hyapp.local/api/proto/user/v1"
|
||||
@ -102,6 +105,23 @@ type h5RechargeOrderRequestBody struct {
|
||||
ReturnURLAlt string `json:"returnUrl"`
|
||||
}
|
||||
|
||||
type temporaryPayLinkRequestBody struct {
|
||||
CoinAmount int64 `json:"coin_amount"`
|
||||
CoinAmountAlt int64 `json:"coinAmount"`
|
||||
USDMinorAmount int64 `json:"usd_minor_amount"`
|
||||
USDMinorAmountAlt int64 `json:"usdMinorAmount"`
|
||||
USDAmount float64 `json:"usd_amount"`
|
||||
USDAmountAlt float64 `json:"usdAmount"`
|
||||
ProviderCode string `json:"provider_code"`
|
||||
ProviderCodeAlt string `json:"providerCode"`
|
||||
PaymentMethodID int64 `json:"payment_method_id"`
|
||||
PaymentMethodAlt int64 `json:"paymentMethodId"`
|
||||
CommandID string `json:"command_id"`
|
||||
CommandIDAlt string `json:"commandId"`
|
||||
ReturnURL string `json:"return_url"`
|
||||
ReturnURLAlt string `json:"returnUrl"`
|
||||
}
|
||||
|
||||
type h5RechargeTxRequestBody struct {
|
||||
DisplayUserID string `json:"display_user_id"`
|
||||
TxHash string `json:"tx_hash"`
|
||||
@ -133,6 +153,14 @@ type h5RechargeOrderData struct {
|
||||
UpdatedAtMS int64 `json:"updated_at_ms"`
|
||||
}
|
||||
|
||||
type temporaryPayLinkData struct {
|
||||
Order h5RechargeOrderData `json:"order"`
|
||||
PaymentURL string `json:"payment_link"`
|
||||
Wrapped bool `json:"wrapped"`
|
||||
RawPayURL string `json:"raw_pay_url,omitempty"`
|
||||
WrappedNote string `json:"wrapped_note,omitempty"`
|
||||
}
|
||||
|
||||
type mifapayNotifyBody struct {
|
||||
MerAccount string `json:"merAccount"`
|
||||
Data string `json:"data"`
|
||||
@ -220,6 +248,128 @@ func (h *Handler) createH5RechargeOrder(writer http.ResponseWriter, request *htt
|
||||
httpkit.WriteOK(writer, request, map[string]any{"order": h5RechargeOrderFromProto(resp.GetOrder())})
|
||||
}
|
||||
|
||||
// listTemporaryPayMethods 返回运营临时支付链接可选的三方支付方式;不需要用户国家和商品档位。
|
||||
func (h *Handler) listTemporaryPayMethods(writer http.ResponseWriter, request *http.Request) {
|
||||
resp, err := h.walletClient.ListThirdPartyPaymentChannels(request.Context(), &walletv1.ListThirdPartyPaymentChannelsRequest{
|
||||
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
Status: "active",
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
providerFilter := normalizeH5PaymentProvider(request.URL.Query().Get("provider_code"), 0)
|
||||
countryFilter := strings.ToUpper(strings.TrimSpace(request.URL.Query().Get("country_code")))
|
||||
methods := make([]thirdPartyPaymentMethodData, 0)
|
||||
for _, channel := range resp.GetChannels() {
|
||||
for _, method := range channel.GetMethods() {
|
||||
if providerFilter != "" && method.GetProviderCode() != providerFilter {
|
||||
continue
|
||||
}
|
||||
if countryFilter != "" && method.GetCountryCode() != countryFilter {
|
||||
continue
|
||||
}
|
||||
methods = append(methods, thirdPartyPaymentMethodFromProto(method))
|
||||
}
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"methods": methods})
|
||||
}
|
||||
|
||||
// createTemporaryPayLink 创建不绑定用户的临时收款链接;支付完成后只用于人工核销。
|
||||
func (h *Handler) createTemporaryPayLink(writer http.ResponseWriter, request *http.Request) {
|
||||
var body temporaryPayLinkRequestBody
|
||||
if !httpkit.Decode(writer, request, &body) {
|
||||
return
|
||||
}
|
||||
coinAmount := firstPositiveInt64(body.CoinAmount, body.CoinAmountAlt)
|
||||
usdMinorAmount := temporaryUSDMinorAmount(body)
|
||||
paymentMethodID := firstPositiveInt64(body.PaymentMethodID, body.PaymentMethodAlt)
|
||||
providerCode := normalizeH5PaymentProvider(firstNonEmptyString(body.ProviderCode, body.ProviderCodeAlt), paymentMethodID)
|
||||
if coinAmount <= 0 || usdMinorAmount <= 0 || paymentMethodID <= 0 || providerCode == "" {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
commandID := strings.TrimSpace(firstNonEmptyString(body.CommandID, body.CommandIDAlt))
|
||||
if commandID == "" {
|
||||
commandID = fmt.Sprintf("h5_temporary_recharge:%s", httpkit.RequestIDFromContext(request.Context()))
|
||||
}
|
||||
resp, err := h.walletClient.CreateTemporaryRechargeOrder(request.Context(), &walletv1.CreateTemporaryRechargeOrderRequest{
|
||||
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
CommandId: commandID,
|
||||
CoinAmount: coinAmount,
|
||||
UsdMinorAmount: usdMinorAmount,
|
||||
ProviderCode: providerCode,
|
||||
PaymentMethodId: paymentMethodID,
|
||||
ReturnUrl: firstNonEmptyString(body.ReturnURL, body.ReturnURLAlt),
|
||||
ClientIp: httpkit.ClientIP(request),
|
||||
Language: h5RechargePaymentLanguage(h5RechargePaymentLanguageQuery(request)),
|
||||
PayerName: "temporary",
|
||||
PayerAccount: "temporary",
|
||||
PayerEmail: temporaryPayPayerEmail(commandID, appcode.FromContext(request.Context())),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
data, ok := h.temporaryPayLinkData(writer, request, resp.GetOrder())
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, data)
|
||||
}
|
||||
|
||||
// getTemporaryPayLink 验证某个临时支付链接状态;wallet-service 会在查询时刷新三方支付状态。
|
||||
func (h *Handler) getTemporaryPayLink(writer http.ResponseWriter, request *http.Request) {
|
||||
orderID := strings.TrimSpace(firstNonEmptyString(request.PathValue("order_id"), request.URL.Query().Get("order_id")))
|
||||
if orderID == "" {
|
||||
httpkit.WriteError(writer, request, http.StatusBadRequest, httpkit.CodeInvalidArgument, "invalid argument")
|
||||
return
|
||||
}
|
||||
resp, err := h.walletClient.GetTemporaryRechargeOrder(request.Context(), &walletv1.GetTemporaryRechargeOrderRequest{
|
||||
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
OrderId: orderID,
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
data, ok := h.temporaryPayLinkData(writer, request, resp.GetOrder())
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
httpkit.WriteOK(writer, request, data)
|
||||
}
|
||||
|
||||
// listTemporaryPayLinks 返回后台管理用的临时支付链接列表;列表不批量刷新上游,单笔验证再触发查单。
|
||||
func (h *Handler) listTemporaryPayLinks(writer http.ResponseWriter, request *http.Request) {
|
||||
query := request.URL.Query()
|
||||
resp, err := h.walletClient.ListTemporaryRechargeOrders(request.Context(), &walletv1.ListTemporaryRechargeOrdersRequest{
|
||||
RequestId: httpkit.RequestIDFromContext(request.Context()),
|
||||
AppCode: appcode.FromContext(request.Context()),
|
||||
Status: strings.TrimSpace(query.Get("status")),
|
||||
ProviderCode: normalizeH5PaymentProvider(query.Get("provider_code"), 0),
|
||||
Keyword: strings.TrimSpace(query.Get("keyword")),
|
||||
Page: int32Query(query, "page", 1),
|
||||
PageSize: int32Query(query, "page_size", 20),
|
||||
})
|
||||
if err != nil {
|
||||
httpkit.WriteRPCError(writer, request, err)
|
||||
return
|
||||
}
|
||||
items := make([]temporaryPayLinkData, 0, len(resp.GetOrders()))
|
||||
for _, order := range resp.GetOrders() {
|
||||
data, ok := h.temporaryPayLinkData(writer, request, order)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
items = append(items, data)
|
||||
}
|
||||
httpkit.WriteOK(writer, request, map[string]any{"orders": items, "total": resp.GetTotal()})
|
||||
}
|
||||
|
||||
// submitH5RechargeTx 提交 USDT tx_hash;无 token 时仍用 display_user_id 校验订单归属。
|
||||
func (h *Handler) submitH5RechargeTx(writer http.ResponseWriter, request *http.Request) {
|
||||
var body h5RechargeTxRequestBody
|
||||
@ -748,6 +898,87 @@ func normalizeH5PaymentProvider(value string, paymentMethodID int64) string {
|
||||
return value
|
||||
}
|
||||
|
||||
func (h *Handler) temporaryPayLinkData(writer http.ResponseWriter, request *http.Request, order *walletv1.ExternalRechargeOrder) (temporaryPayLinkData, bool) {
|
||||
data := temporaryPayLinkData{Order: h5RechargeOrderFromProto(order), PaymentURL: strings.TrimSpace(order.GetPayUrl())}
|
||||
if data.PaymentURL == "" || isHTTPPayURL(data.PaymentURL) {
|
||||
return data, true
|
||||
}
|
||||
wrappedURL, err := h.uploadTemporaryPaySchemeWrapper(request, order.GetOrderId(), data.PaymentURL)
|
||||
if err != nil {
|
||||
httpkit.WriteError(writer, request, http.StatusBadGateway, httpkit.CodeUpstreamError, "temporary payment wrapper is not configured")
|
||||
return temporaryPayLinkData{}, false
|
||||
}
|
||||
data.RawPayURL = data.PaymentURL
|
||||
data.PaymentURL = wrappedURL
|
||||
data.Wrapped = true
|
||||
data.WrappedNote = "原始支付链接是 app scheme,已生成 COS 中转 HTML。"
|
||||
return data, true
|
||||
}
|
||||
|
||||
func (h *Handler) uploadTemporaryPaySchemeWrapper(request *http.Request, orderID string, rawPayURL string) (string, error) {
|
||||
if h.objectUploader == nil {
|
||||
return "", fmt.Errorf("object uploader is not configured")
|
||||
}
|
||||
orderID = strings.TrimSpace(orderID)
|
||||
if orderID == "" {
|
||||
return "", fmt.Errorf("order_id is required")
|
||||
}
|
||||
body := temporaryPaySchemeHTML(rawPayURL)
|
||||
key := fmt.Sprintf("recharge/temporary-pay/%s.html", orderID)
|
||||
return h.objectUploader.PutObject(request.Context(), key, bytes.NewReader([]byte(body)), int64(len(body)), "text/html; charset=utf-8")
|
||||
}
|
||||
|
||||
func temporaryPaySchemeHTML(rawPayURL string) string {
|
||||
rawPayURL = strings.TrimSpace(rawPayURL)
|
||||
payURLJSON, _ := json.Marshal(rawPayURL)
|
||||
return fmt.Sprintf(`<!doctype html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
<title>打开支付</title>
|
||||
</head>
|
||||
<body>
|
||||
<p>正在打开支付页面,如果没有自动跳转,请点击下面的链接。</p>
|
||||
<p><a href="%s">打开支付</a></p>
|
||||
<script>window.location.replace(%s);</script>
|
||||
</body>
|
||||
</html>`, html.EscapeString(rawPayURL), string(payURLJSON))
|
||||
}
|
||||
|
||||
func isHTTPPayURL(value string) bool {
|
||||
parsed, err := url.Parse(strings.TrimSpace(value))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return parsed.Scheme == "http" || parsed.Scheme == "https"
|
||||
}
|
||||
|
||||
func temporaryUSDMinorAmount(body temporaryPayLinkRequestBody) int64 {
|
||||
if value := firstPositiveInt64(body.USDMinorAmount, body.USDMinorAmountAlt); value > 0 {
|
||||
return value
|
||||
}
|
||||
for _, amount := range []float64{body.USDAmount, body.USDAmountAlt} {
|
||||
if amount > 0 {
|
||||
return int64(amount*100 + 0.5)
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func temporaryPayPayerEmail(commandID string, app string) string {
|
||||
localPart := h5RechargeEmailLocalPart(strings.TrimPrefix(commandID, "h5_temporary_recharge:"))
|
||||
return localPart + "@" + h5RechargeEmailDomainLabel(app) + ".temporary"
|
||||
}
|
||||
|
||||
func int32Query(values url.Values, key string, fallback int32) int32 {
|
||||
parsed, err := strconv.Atoi(strings.TrimSpace(values.Get(key)))
|
||||
if err != nil || parsed <= 0 {
|
||||
return fallback
|
||||
}
|
||||
return int32(parsed)
|
||||
}
|
||||
|
||||
func v5PayNotifyFields(payload map[string]any) map[string]string {
|
||||
fields := make(map[string]string, len(payload))
|
||||
for key, value := range payload {
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package walletapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"hyapp/services/gateway-service/internal/client"
|
||||
@ -17,6 +19,12 @@ type Handler struct {
|
||||
userProfileClient client.UserProfileClient
|
||||
userHostClient client.UserHostClient
|
||||
imGroupIDPrefix string
|
||||
objectUploader ObjectUploader
|
||||
}
|
||||
|
||||
// ObjectUploader 是临时支付链接包装 app scheme 时依赖的对象存储能力。
|
||||
type ObjectUploader interface {
|
||||
PutObject(ctx context.Context, key string, reader io.Reader, sizeBytes int64, contentType string) (string, error)
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@ -27,6 +35,7 @@ type Config struct {
|
||||
UserProfileClient client.UserProfileClient
|
||||
UserHostClient client.UserHostClient
|
||||
IMGroupIDPrefix string
|
||||
ObjectUploader ObjectUploader
|
||||
}
|
||||
|
||||
func New(config Config) *Handler {
|
||||
@ -38,6 +47,7 @@ func New(config Config) *Handler {
|
||||
userProfileClient: config.UserProfileClient,
|
||||
userHostClient: config.UserHostClient,
|
||||
imGroupIDPrefix: config.IMGroupIDPrefix,
|
||||
objectUploader: config.ObjectUploader,
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,6 +59,10 @@ func (h *Handler) WalletHandlers() httproutes.WalletHandlers {
|
||||
GetH5RechargeContext: h.getH5RechargeContext,
|
||||
ListH5RechargeOptions: h.listH5RechargeOptions,
|
||||
CreateH5RechargeOrder: h.createH5RechargeOrder,
|
||||
ListTemporaryPayMethods: h.listTemporaryPayMethods,
|
||||
CreateTemporaryPayLink: h.createTemporaryPayLink,
|
||||
GetTemporaryPayLink: h.getTemporaryPayLink,
|
||||
ListTemporaryPayLinks: h.listTemporaryPayLinks,
|
||||
SubmitH5RechargeTx: h.submitH5RechargeTx,
|
||||
GetH5RechargeOrder: h.getH5RechargeOrder,
|
||||
HandleMifapayNotify: h.handleMifapayNotify,
|
||||
|
||||
@ -302,17 +302,25 @@ func roomEventFromEnvelope(envelope *roomeventsv1.EventEnvelope) (tencentim.Room
|
||||
return tencentim.RoomEvent{}, false, err
|
||||
}
|
||||
base.Attributes = map[string]string{
|
||||
"gift_id": body.GetGiftId(),
|
||||
"gift_count": fmt.Sprintf("%d", body.GetGiftCount()),
|
||||
"coin_spent": fmt.Sprintf("%d", body.GetCoinSpent()),
|
||||
"billing_receipt_id": body.GetBillingReceiptId(),
|
||||
"target_gift_value": fmt.Sprintf("%d", body.GetTargetGiftValue()),
|
||||
"gift_type_code": body.GetGiftTypeCode(),
|
||||
"cp_relation_type": body.GetCpRelationType(),
|
||||
"gift_name": body.GetGiftName(),
|
||||
"gift_icon_url": body.GetGiftIconUrl(),
|
||||
"gift_animation_url": body.GetGiftAnimationUrl(),
|
||||
"gift_effect_types": string(effectTypesJSON),
|
||||
"gift_id": body.GetGiftId(),
|
||||
"gift_count": fmt.Sprintf("%d", body.GetGiftCount()),
|
||||
"coin_spent": fmt.Sprintf("%d", body.GetCoinSpent()),
|
||||
"billing_receipt_id": body.GetBillingReceiptId(),
|
||||
"target_gift_value": fmt.Sprintf("%d", body.GetTargetGiftValue()),
|
||||
"gift_type_code": body.GetGiftTypeCode(),
|
||||
"cp_relation_type": body.GetCpRelationType(),
|
||||
"gift_name": body.GetGiftName(),
|
||||
"gift_icon_url": body.GetGiftIconUrl(),
|
||||
"gift_animation_url": body.GetGiftAnimationUrl(),
|
||||
"gift_effect_types": string(effectTypesJSON),
|
||||
"sender_name": body.GetSenderName(),
|
||||
"sender_avatar": body.GetSenderAvatar(),
|
||||
"sender_display_user_id": body.GetSenderDisplayUserId(),
|
||||
"sender_pretty_display_user_id": body.GetSenderPrettyDisplayUserId(),
|
||||
"receiver_nickname": body.GetReceiverNickname(),
|
||||
"receiver_avatar": body.GetReceiverAvatar(),
|
||||
"receiver_display_user_id": body.GetReceiverDisplayUserId(),
|
||||
"receiver_pretty_display_user_id": body.GetReceiverPrettyDisplayUserId(),
|
||||
}
|
||||
return base, true, nil
|
||||
case "RoomHeatChanged":
|
||||
|
||||
@ -90,12 +90,18 @@ func TestRoomBackgroundChangedPublishesDedicatedIMEvent(t *testing.T) {
|
||||
|
||||
func TestRoomGiftSentCarriesTargetGiftValueInIMAttributes(t *testing.T) {
|
||||
record, err := outbox.Build("room-gift-value", "RoomGiftSent", 8, time.Now(), &roomeventsv1.RoomGiftSent{
|
||||
SenderUserId: 1001,
|
||||
TargetUserId: 1002,
|
||||
GiftId: "gift_rose",
|
||||
GiftCount: 1,
|
||||
GiftValue: 117,
|
||||
TargetGiftValue: 367,
|
||||
SenderUserId: 1001,
|
||||
TargetUserId: 1002,
|
||||
GiftId: "gift_rose",
|
||||
GiftCount: 1,
|
||||
GiftValue: 117,
|
||||
TargetGiftValue: 367,
|
||||
SenderName: "Robot Sender",
|
||||
SenderAvatar: "https://cdn.example/sender.png",
|
||||
SenderDisplayUserId: "100001",
|
||||
ReceiverNickname: "Robot Receiver",
|
||||
ReceiverAvatar: "https://cdn.example/receiver.png",
|
||||
ReceiverDisplayUserId: "100002",
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Build RoomGiftSent envelope failed: %v", err)
|
||||
@ -111,6 +117,12 @@ func TestRoomGiftSentCarriesTargetGiftValueInIMAttributes(t *testing.T) {
|
||||
if event.EventType != "room_gift_sent" || event.GiftValue != 117 || event.Attributes["target_gift_value"] != "367" {
|
||||
t.Fatalf("gift IM event target gift value mismatch: %+v", event)
|
||||
}
|
||||
if event.Attributes["sender_name"] != "Robot Sender" || event.Attributes["sender_avatar"] != "https://cdn.example/sender.png" || event.Attributes["sender_display_user_id"] != "100001" {
|
||||
t.Fatalf("gift IM event sender display fields mismatch: %+v", event.Attributes)
|
||||
}
|
||||
if event.Attributes["receiver_nickname"] != "Robot Receiver" || event.Attributes["receiver_avatar"] != "https://cdn.example/receiver.png" || event.Attributes["receiver_display_user_id"] != "100002" {
|
||||
t.Fatalf("gift IM event receiver display fields mismatch: %+v", event.Attributes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoomHeatAndRankChangedPublishDisplayIMEvents(t *testing.T) {
|
||||
|
||||
@ -131,6 +131,8 @@ type JoinRoom struct {
|
||||
ActorCountryID int64 `json:"actor_country_id,omitempty"`
|
||||
// ActorRegionID 是 gateway 从 user-service 注入的真实区域;房间 visible_region_id 不能代替用户国家。
|
||||
ActorRegionID int64 `json:"actor_region_id,omitempty"`
|
||||
// ActorIsRobot 标记本次进房由房间机器人调度触发,统计消费者据此排除活跃用户口径。
|
||||
ActorIsRobot bool `json:"actor_is_robot,omitempty"`
|
||||
// EntryVehicle 是 gateway 在进房时解析出的当前有效佩戴座驾快照,用于进房 IM。
|
||||
EntryVehicle EntryVehicleSnapshot `json:"entry_vehicle,omitempty"`
|
||||
}
|
||||
@ -432,6 +434,10 @@ type SendGift struct {
|
||||
TargetAgencyOwnerUserID int64 `json:"target_agency_owner_user_id,omitempty"`
|
||||
// TargetHostScopes 是 gateway 为批量送礼逐接收方固化的主播工资入账快照。
|
||||
TargetHostScopes []GiftTargetHostScope `json:"target_host_scopes,omitempty"`
|
||||
// SenderDisplayProfile 是 gateway 在入口读取的送礼人展示快照;room-service 不把它写入 RoomState。
|
||||
SenderDisplayProfile GiftDisplayProfile `json:"sender_display_profile,omitempty"`
|
||||
// TargetDisplayProfiles 是 gateway 在入口读取的收礼人展示快照;按 target_user_id 对齐多目标 IM。
|
||||
TargetDisplayProfiles []GiftDisplayProfile `json:"target_display_profiles,omitempty"`
|
||||
// BillingReceiptID 是 wallet-service 成功落账后的回执,用于排障和恢复审计。
|
||||
BillingReceiptID string `json:"billing_receipt_id,omitempty"`
|
||||
// CoinSpent 是 sender COIN 实际扣减值,来自 wallet-service 服务端价格。
|
||||
@ -503,6 +509,21 @@ type GiftTargetHostScope struct {
|
||||
TargetAgencyOwnerUserID int64 `json:"target_agency_owner_user_id,omitempty"`
|
||||
}
|
||||
|
||||
// GiftDisplayProfile 是送礼入口固化的用户展示快照。
|
||||
// 它只服务 IM 和历史事件展示兜底,不参与权限、账务、统计或 Room Cell 核心状态判定。
|
||||
type GiftDisplayProfile struct {
|
||||
// UserID 是快照归属用户,收礼多目标时用它对齐具体 target_user_id。
|
||||
UserID int64 `json:"user_id"`
|
||||
// Username 是客户端优先展示的昵称;为空时客户端可继续回退 display_user_id。
|
||||
Username string `json:"username,omitempty"`
|
||||
// Avatar 是送礼瞬间的头像 URL,IM 飘窗可直接渲染,不再临时回查用户服务。
|
||||
Avatar string `json:"avatar,omitempty"`
|
||||
// DisplayUserID 是当前 active 短号,昵称缺失时给 Flutter 兜底展示。
|
||||
DisplayUserID string `json:"display_user_id,omitempty"`
|
||||
// PrettyDisplayUserID 是当前靓号展示值,保留给后续客户端按展示策略选择。
|
||||
PrettyDisplayUserID string `json:"pretty_display_user_id,omitempty"`
|
||||
}
|
||||
|
||||
// RocketRewardGrant 记录发射命令中已经结算出的资源组发放结果。
|
||||
type RocketRewardGrant struct {
|
||||
RewardRole string `json:"reward_role"`
|
||||
@ -588,6 +609,9 @@ func IdempotencyPayload(payload []byte) ([]byte, error) {
|
||||
delete(values, "gateway_node_id")
|
||||
delete(values, "session_id")
|
||||
delete(values, "sent_at_ms")
|
||||
// 展示快照来自 gateway 对 user-service 的读取结果,不改变扣费和房间状态语义;重试同一 command_id 时不能因为昵称头像变化冲突。
|
||||
delete(values, "sender_display_profile")
|
||||
delete(values, "target_display_profiles")
|
||||
// SendGift 的以下字段由 wallet-service 结算后写入 command log,不属于客户端请求幂等语义。
|
||||
delete(values, "billing_receipt_id")
|
||||
delete(values, "coin_spent")
|
||||
|
||||
@ -624,8 +624,9 @@ func (s *Service) joinRobotRoomUser(ctx context.Context, config RobotRoomConfig,
|
||||
role = "owner"
|
||||
}
|
||||
if _, err := s.JoinRoom(ctx, &roomv1.JoinRoomRequest{
|
||||
Meta: robotRoomCommandMeta(config, userID, suffix),
|
||||
Role: role,
|
||||
Meta: robotRoomCommandMeta(config, userID, suffix),
|
||||
Role: role,
|
||||
ActorIsRobot: true,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
roomeventsv1 "hyapp.local/api/proto/events/room/v1"
|
||||
roomv1 "hyapp.local/api/proto/room/v1"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/services/room-service/internal/integration"
|
||||
@ -124,6 +126,59 @@ func TestAdminCreateRobotRoomUsesCandidatePoolAndActiveCount(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAdminCreateRobotRoomMarksRobotJoinOutbox(t *testing.T) {
|
||||
ctx := appcode.WithContext(context.Background(), appcode.Default)
|
||||
repository := mysqltest.NewRepository(t)
|
||||
svc := roomservice.New(roomservice.Config{
|
||||
NodeID: "node-admin-robot-room-join-outbox-test",
|
||||
LeaseTTL: 10 * time.Second,
|
||||
RankLimit: 20,
|
||||
SnapshotEveryN: 1,
|
||||
}, router.NewMemoryDirectory(), repository, followTestWallet{}, integration.NewNoopRoomEventPublisher(), integration.NewNoopOutboxPublisher())
|
||||
|
||||
_, err := svc.AdminCreateRobotRoom(ctx, &roomv1.AdminCreateRobotRoomRequest{
|
||||
Meta: roomservice.NewRequestMeta("", 9001),
|
||||
OwnerRobotUserId: 2001,
|
||||
CandidateRobotUserIds: []int64{2001},
|
||||
MinRobotCount: 1,
|
||||
MaxRobotCount: 1,
|
||||
RoomName: "Robot Join Outbox",
|
||||
RoomAvatar: testRoomCoverURL,
|
||||
VisibleRegionId: 686,
|
||||
OwnerCountryCode: "ae",
|
||||
GiftRule: &roomv1.AdminRobotRoomGiftRule{
|
||||
GiftIds: []string{"84"},
|
||||
NormalGiftIntervalMs: 10000,
|
||||
},
|
||||
AdminId: 9001,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("AdminCreateRobotRoom failed: %v", err)
|
||||
}
|
||||
|
||||
records, err := repository.ListPendingOutbox(ctx, 20)
|
||||
if err != nil {
|
||||
t.Fatalf("list pending outbox failed: %v", err)
|
||||
}
|
||||
joinEvents := 0
|
||||
for _, record := range records {
|
||||
if record.EventType != "RoomUserJoined" {
|
||||
continue
|
||||
}
|
||||
joinEvents++
|
||||
var joined roomeventsv1.RoomUserJoined
|
||||
if err := proto.Unmarshal(record.Envelope.GetBody(), &joined); err != nil {
|
||||
t.Fatalf("decode room join event failed: %v", err)
|
||||
}
|
||||
if joined.GetUserId() == 2001 && !joined.GetIsRobot() {
|
||||
t.Fatalf("robot join outbox must mark is_robot=true: %+v", &joined)
|
||||
}
|
||||
}
|
||||
if joinEvents == 0 {
|
||||
t.Fatalf("robot room creation should write RoomUserJoined outbox")
|
||||
}
|
||||
}
|
||||
|
||||
func occupiedSeatUserCount(snapshot *roomv1.RoomSnapshot) int {
|
||||
count := 0
|
||||
for _, seat := range snapshot.GetMicSeats() {
|
||||
|
||||
@ -84,6 +84,8 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
|
||||
TargetHostRegionID: req.GetTargetHostRegionId(),
|
||||
TargetAgencyOwnerUserID: req.GetTargetAgencyOwnerUserId(),
|
||||
TargetHostScopes: giftTargetHostScopesFromProto(req.GetTargetHostScopes()),
|
||||
SenderDisplayProfile: giftDisplayProfileFromProto(req.GetSenderDisplayProfile()),
|
||||
TargetDisplayProfiles: giftDisplayProfilesFromProto(req.GetTargetDisplayProfiles()),
|
||||
RobotGift: robotOptions.Enabled && !robotOptions.RealRoomHeat,
|
||||
RobotWalletGift: robotOptions.Enabled,
|
||||
SyntheticLuckyGift: robotOptions.Enabled && strings.TrimSpace(req.GetPoolId()) != "",
|
||||
@ -251,25 +253,34 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
|
||||
// 送礼事件按 target 拆分,保证 IM、统计和礼物墙消费者拿到准确的接收方和账务回执。
|
||||
giftEvents := make([]outbox.Record, 0, len(targetBillings))
|
||||
for _, targetBilling := range targetBillings {
|
||||
targetDisplayProfile := giftDisplayProfileForUser(cmd.TargetDisplayProfiles, targetBilling.TargetUserID)
|
||||
giftEvent, err := outbox.Build(current.RoomID, "RoomGiftSent", current.Version, now, &roomeventsv1.RoomGiftSent{
|
||||
SenderUserId: cmd.ActorUserID(),
|
||||
TargetUserId: targetBilling.TargetUserID,
|
||||
GiftId: cmd.GiftID,
|
||||
PoolId: cmd.PoolID,
|
||||
GiftCount: cmd.GiftCount,
|
||||
GiftValue: targetBilling.Billing.GetHeatValue(),
|
||||
CoinSpent: targetBilling.Billing.GetCoinSpent(),
|
||||
BillingReceiptId: targetBilling.Billing.GetBillingReceiptId(),
|
||||
VisibleRegionId: roomMeta.VisibleRegionID,
|
||||
CountryId: cmd.SenderCountryID,
|
||||
RegionId: firstNonZeroInt64(cmd.SenderRegionID, roomMeta.VisibleRegionID),
|
||||
CommandId: targetBilling.CommandID,
|
||||
GiftTypeCode: targetBilling.Billing.GetGiftTypeCode(),
|
||||
CpRelationType: targetBilling.Billing.GetCpRelationType(),
|
||||
GiftName: targetBilling.Billing.GetGiftName(),
|
||||
GiftIconUrl: targetBilling.Billing.GetGiftIconUrl(),
|
||||
GiftAnimationUrl: targetBilling.Billing.GetGiftAnimationUrl(),
|
||||
TargetGiftValue: targetCurrentGiftValues[targetBilling.TargetUserID],
|
||||
SenderUserId: cmd.ActorUserID(),
|
||||
TargetUserId: targetBilling.TargetUserID,
|
||||
GiftId: cmd.GiftID,
|
||||
PoolId: cmd.PoolID,
|
||||
GiftCount: cmd.GiftCount,
|
||||
GiftValue: targetBilling.Billing.GetHeatValue(),
|
||||
CoinSpent: targetBilling.Billing.GetCoinSpent(),
|
||||
BillingReceiptId: targetBilling.Billing.GetBillingReceiptId(),
|
||||
VisibleRegionId: roomMeta.VisibleRegionID,
|
||||
CountryId: cmd.SenderCountryID,
|
||||
RegionId: firstNonZeroInt64(cmd.SenderRegionID, roomMeta.VisibleRegionID),
|
||||
CommandId: targetBilling.CommandID,
|
||||
GiftTypeCode: targetBilling.Billing.GetGiftTypeCode(),
|
||||
CpRelationType: targetBilling.Billing.GetCpRelationType(),
|
||||
GiftName: targetBilling.Billing.GetGiftName(),
|
||||
GiftIconUrl: targetBilling.Billing.GetGiftIconUrl(),
|
||||
GiftAnimationUrl: targetBilling.Billing.GetGiftAnimationUrl(),
|
||||
TargetGiftValue: targetCurrentGiftValues[targetBilling.TargetUserID],
|
||||
SenderName: giftDisplayName(cmd.SenderDisplayProfile),
|
||||
SenderAvatar: strings.TrimSpace(cmd.SenderDisplayProfile.Avatar),
|
||||
SenderDisplayUserId: strings.TrimSpace(cmd.SenderDisplayProfile.DisplayUserID),
|
||||
SenderPrettyDisplayUserId: strings.TrimSpace(cmd.SenderDisplayProfile.PrettyDisplayUserID),
|
||||
ReceiverNickname: giftDisplayName(targetDisplayProfile),
|
||||
ReceiverAvatar: strings.TrimSpace(targetDisplayProfile.Avatar),
|
||||
ReceiverDisplayUserId: strings.TrimSpace(targetDisplayProfile.DisplayUserID),
|
||||
ReceiverPrettyDisplayUserId: strings.TrimSpace(targetDisplayProfile.PrettyDisplayUserID),
|
||||
// effect_types 来自后台礼物配置,房间事件必须原样带出,后续 activity-service 才能识别全服广播标识。
|
||||
GiftEffectTypes: targetBilling.Billing.GetGiftEffectTypes(),
|
||||
IsRobotGift: cmd.RobotWalletGift,
|
||||
@ -368,6 +379,7 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
|
||||
}
|
||||
}
|
||||
|
||||
firstTargetDisplayProfile := giftDisplayProfileForUser(cmd.TargetDisplayProfiles, cmd.TargetUserID)
|
||||
result := mutationResult{
|
||||
snapshot: current.ToProto(),
|
||||
billingReceiptID: billing.GetBillingReceiptId(),
|
||||
@ -410,24 +422,32 @@ func (s *Service) sendGift(ctx context.Context, req *roomv1.SendGiftRequest, rob
|
||||
RoomHeat: current.Heat,
|
||||
RoomVersion: current.Version,
|
||||
Attributes: map[string]string{
|
||||
"gift_id": cmd.GiftID,
|
||||
"pool_id": cmd.PoolID,
|
||||
"gift_count": fmt.Sprintf("%d", cmd.GiftCount),
|
||||
"billing_receipt_id": billing.GetBillingReceiptId(),
|
||||
"coin_spent": fmt.Sprintf("%d", settledCommand.CoinSpent),
|
||||
"target_count": fmt.Sprintf("%d", len(cmd.TargetUserIDs)),
|
||||
"target_user_ids": giftTargetUserIDsAttribute(cmd.TargetUserIDs),
|
||||
"price_version": settledCommand.PriceVersion,
|
||||
"host_period_diamond_added": fmt.Sprintf("%d", settledCommand.HostPeriodDiamondAdded),
|
||||
"host_period_cycle_key": settledCommand.HostPeriodCycleKey,
|
||||
"gift_type_code": billing.GetGiftTypeCode(),
|
||||
"cp_relation_type": billing.GetCpRelationType(),
|
||||
"gift_name": billing.GetGiftName(),
|
||||
"gift_icon_url": billing.GetGiftIconUrl(),
|
||||
"gift_animation_url": billing.GetGiftAnimationUrl(),
|
||||
"target_gift_value": fmt.Sprintf("%d", targetCurrentGiftValues[cmd.TargetUserID]),
|
||||
"is_robot_gift": fmt.Sprintf("%t", cmd.RobotWalletGift),
|
||||
"synthetic_lucky_gift": fmt.Sprintf("%t", cmd.SyntheticLuckyGift),
|
||||
"gift_id": cmd.GiftID,
|
||||
"pool_id": cmd.PoolID,
|
||||
"gift_count": fmt.Sprintf("%d", cmd.GiftCount),
|
||||
"billing_receipt_id": billing.GetBillingReceiptId(),
|
||||
"coin_spent": fmt.Sprintf("%d", settledCommand.CoinSpent),
|
||||
"target_count": fmt.Sprintf("%d", len(cmd.TargetUserIDs)),
|
||||
"target_user_ids": giftTargetUserIDsAttribute(cmd.TargetUserIDs),
|
||||
"price_version": settledCommand.PriceVersion,
|
||||
"host_period_diamond_added": fmt.Sprintf("%d", settledCommand.HostPeriodDiamondAdded),
|
||||
"host_period_cycle_key": settledCommand.HostPeriodCycleKey,
|
||||
"gift_type_code": billing.GetGiftTypeCode(),
|
||||
"cp_relation_type": billing.GetCpRelationType(),
|
||||
"gift_name": billing.GetGiftName(),
|
||||
"gift_icon_url": billing.GetGiftIconUrl(),
|
||||
"gift_animation_url": billing.GetGiftAnimationUrl(),
|
||||
"target_gift_value": fmt.Sprintf("%d", targetCurrentGiftValues[cmd.TargetUserID]),
|
||||
"is_robot_gift": fmt.Sprintf("%t", cmd.RobotWalletGift),
|
||||
"synthetic_lucky_gift": fmt.Sprintf("%t", cmd.SyntheticLuckyGift),
|
||||
"sender_name": giftDisplayName(cmd.SenderDisplayProfile),
|
||||
"sender_avatar": strings.TrimSpace(cmd.SenderDisplayProfile.Avatar),
|
||||
"sender_display_user_id": strings.TrimSpace(cmd.SenderDisplayProfile.DisplayUserID),
|
||||
"sender_pretty_display_user_id": strings.TrimSpace(cmd.SenderDisplayProfile.PrettyDisplayUserID),
|
||||
"receiver_nickname": giftDisplayName(firstTargetDisplayProfile),
|
||||
"receiver_avatar": strings.TrimSpace(firstTargetDisplayProfile.Avatar),
|
||||
"receiver_display_user_id": strings.TrimSpace(firstTargetDisplayProfile.DisplayUserID),
|
||||
"receiver_pretty_display_user_id": strings.TrimSpace(firstTargetDisplayProfile.PrettyDisplayUserID),
|
||||
},
|
||||
},
|
||||
}
|
||||
@ -781,6 +801,56 @@ func giftTargetHostScopesFromProto(scopes []*roomv1.SendGiftTargetHostScope) []c
|
||||
return result
|
||||
}
|
||||
|
||||
func giftDisplayProfileFromProto(item *roomv1.SendGiftDisplayProfile) command.GiftDisplayProfile {
|
||||
if item == nil || item.GetUserId() <= 0 {
|
||||
return command.GiftDisplayProfile{}
|
||||
}
|
||||
// 展示快照只裁剪空白字符,不做业务兜底;兜底顺序统一放在 giftDisplayName,避免事件字段互相不一致。
|
||||
return command.GiftDisplayProfile{
|
||||
UserID: item.GetUserId(),
|
||||
Username: strings.TrimSpace(item.GetUsername()),
|
||||
Avatar: strings.TrimSpace(item.GetAvatar()),
|
||||
DisplayUserID: strings.TrimSpace(item.GetDisplayUserId()),
|
||||
PrettyDisplayUserID: strings.TrimSpace(item.GetPrettyDisplayUserId()),
|
||||
}
|
||||
}
|
||||
|
||||
func giftDisplayProfilesFromProto(items []*roomv1.SendGiftDisplayProfile) []command.GiftDisplayProfile {
|
||||
result := make([]command.GiftDisplayProfile, 0, len(items))
|
||||
seen := make(map[int64]bool, len(items))
|
||||
for _, item := range items {
|
||||
profile := giftDisplayProfileFromProto(item)
|
||||
if profile.UserID <= 0 || seen[profile.UserID] {
|
||||
continue
|
||||
}
|
||||
seen[profile.UserID] = true
|
||||
result = append(result, profile)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func giftDisplayProfileForUser(profiles []command.GiftDisplayProfile, userID int64) command.GiftDisplayProfile {
|
||||
if userID <= 0 {
|
||||
return command.GiftDisplayProfile{}
|
||||
}
|
||||
for _, profile := range profiles {
|
||||
if profile.UserID == userID {
|
||||
return profile
|
||||
}
|
||||
}
|
||||
return command.GiftDisplayProfile{UserID: userID}
|
||||
}
|
||||
|
||||
func giftDisplayName(profile command.GiftDisplayProfile) string {
|
||||
// Flutter 的 IM 解析已支持 sender_name/receiver_nickname;这里按用户昵称、靓号、短号依次兜底,避免跨房飘窗直接落到 User <id>。
|
||||
for _, value := range []string{profile.Username, profile.PrettyDisplayUserID, profile.DisplayUserID} {
|
||||
if trimmed := strings.TrimSpace(value); trimmed != "" {
|
||||
return trimmed
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func giftTargetHostScopeFor(cmd command.SendGift, targetUserID int64) command.GiftTargetHostScope {
|
||||
for _, scope := range cmd.TargetHostScopes {
|
||||
if scope.TargetUserID == targetUserID {
|
||||
|
||||
@ -536,8 +536,9 @@ func randomHumanRoomTargetOnline(config HumanRoomRobotConfig) int {
|
||||
|
||||
func (s *Service) joinHumanRoomRobot(ctx context.Context, roomID string, userID int64, seatNo int32, suffix string) error {
|
||||
if _, err := s.JoinRoom(ctx, &roomv1.JoinRoomRequest{
|
||||
Meta: humanRoomRobotCommandMeta(HumanRoomRobotConfig{AppCode: appcode.FromContext(ctx)}, roomID, userID, "join:"+suffix),
|
||||
Role: "audience",
|
||||
Meta: humanRoomRobotCommandMeta(HumanRoomRobotConfig{AppCode: appcode.FromContext(ctx)}, roomID, userID, "join:"+suffix),
|
||||
Role: "audience",
|
||||
ActorIsRobot: true,
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@ -29,6 +29,7 @@ func (s *Service) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*r
|
||||
Role: req.GetRole(),
|
||||
ActorCountryID: req.GetActorCountryId(),
|
||||
ActorRegionID: req.GetActorRegionId(),
|
||||
ActorIsRobot: req.GetActorIsRobot(),
|
||||
// entry_vehicle 来自 gateway 入房瞬间的 wallet 快照,写入 command log 后可稳定重放。
|
||||
EntryVehicle: entryVehicleSnapshotFromProto(req.GetEntryVehicle()),
|
||||
}
|
||||
@ -82,6 +83,8 @@ func (s *Service) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*r
|
||||
VisibleRegionId: current.VisibleRegionID,
|
||||
CountryId: cmd.ActorCountryID,
|
||||
RegionId: firstNonZeroInt64(cmd.ActorRegionID, current.VisibleRegionID),
|
||||
// 机器人进房仍然需要 outbox 驱动 IM 展示和恢复,但不能进入真人活跃统计。
|
||||
IsRobot: cmd.ActorIsRobot,
|
||||
// outbox 事件必须带座驾快照;否则异步补偿投递 IM 时会丢失入场座驾。
|
||||
EntryVehicle: eventEntryVehicleFromCommand(cmd.EntryVehicle),
|
||||
})
|
||||
|
||||
@ -418,6 +418,10 @@ func roomJoinActiveEvent(body []byte) (mysqlstorage.UserActiveEvent, bool, error
|
||||
if err := proto.Unmarshal(envelope.GetBody(), &joined); err != nil {
|
||||
return mysqlstorage.UserActiveEvent{}, false, err
|
||||
}
|
||||
if joined.GetIsRobot() {
|
||||
// 房间机器人进房只服务房间热闹度和 IM 展示,不代表真人用户活跃;这里返回 ok=false,让 room outbox 消费继续提交位点但不写统计聚合。
|
||||
return mysqlstorage.UserActiveEvent{}, false, nil
|
||||
}
|
||||
return mysqlstorage.UserActiveEvent{
|
||||
AppCode: envelope.GetAppCode(),
|
||||
EventID: envelope.GetEventId(),
|
||||
|
||||
@ -252,6 +252,37 @@ func TestLocalStatisticsDataScreenFlow(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRoomJoinActiveEventSkipsRobotJoin(t *testing.T) {
|
||||
occurredAt := time.Date(2026, 6, 25, 8, 0, 0, 0, time.UTC).UnixMilli()
|
||||
|
||||
active, ok, err := roomJoinActiveEvent(roomJoinMessage(t, "lalu", "room_join_real_1", "room_1", occurredAt, &roomeventsv1.RoomUserJoined{
|
||||
UserId: 42,
|
||||
Role: "audience",
|
||||
CountryId: 86,
|
||||
RegionId: 210,
|
||||
}))
|
||||
if err != nil || !ok {
|
||||
t.Fatalf("real room join should produce active event: ok=%v err=%v", ok, err)
|
||||
}
|
||||
if active.UserID != 42 || active.CountryID != 86 || active.RegionID != 210 || active.EventType != "RoomUserJoined" {
|
||||
t.Fatalf("real room join active payload mismatch: %+v", active)
|
||||
}
|
||||
|
||||
active, ok, err = roomJoinActiveEvent(roomJoinMessage(t, "lalu", "room_join_robot_1", "room_1", occurredAt, &roomeventsv1.RoomUserJoined{
|
||||
UserId: 88001,
|
||||
Role: "audience",
|
||||
CountryId: 86,
|
||||
RegionId: 210,
|
||||
IsRobot: true,
|
||||
}))
|
||||
if err != nil {
|
||||
t.Fatalf("robot room join decode failed: %v", err)
|
||||
}
|
||||
if ok {
|
||||
t.Fatalf("robot room join must not produce active event: %+v", active)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalSelfGameStatisticsFlow(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
_, file, _, _ := runtime.Caller(0)
|
||||
@ -475,6 +506,27 @@ func roomGiftMessage(t *testing.T, appCode string, eventID string, roomID string
|
||||
return body
|
||||
}
|
||||
|
||||
func roomJoinMessage(t *testing.T, appCode string, eventID string, roomID string, occurredAt int64, joined *roomeventsv1.RoomUserJoined) []byte {
|
||||
t.Helper()
|
||||
joinedBody, err := proto.Marshal(joined)
|
||||
if err != nil {
|
||||
t.Fatalf("marshal room join failed: %v", err)
|
||||
}
|
||||
body, err := roommq.EncodeRoomOutboxMessage(&roomeventsv1.EventEnvelope{
|
||||
EventId: eventID,
|
||||
RoomId: roomID,
|
||||
EventType: "RoomUserJoined",
|
||||
RoomVersion: 1,
|
||||
OccurredAtMs: occurredAt,
|
||||
Body: joinedBody,
|
||||
AppCode: appCode,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("encode room join message failed: %v", err)
|
||||
}
|
||||
return body
|
||||
}
|
||||
|
||||
func gameMessage(appCode string, orderID string, userID int64, opType string, amount int64, countryID int64, regionID int64, occurredAt int64) gamemq.GameOutboxMessage {
|
||||
return gamemq.GameOutboxMessage{
|
||||
AppCode: appCode,
|
||||
|
||||
@ -31,6 +31,20 @@ ON DUPLICATE KEY UPDATE
|
||||
status = VALUES(status),
|
||||
updated_at_ms = VALUES(updated_at_ms);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS auth_risk_configs (
|
||||
app_code VARCHAR(32) NOT NULL PRIMARY KEY COMMENT '应用编码,用于多租户隔离',
|
||||
max_accounts_per_device INT NOT NULL DEFAULT 1 COMMENT '单设备最大注册账号数',
|
||||
updated_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '最近修改后台管理员 ID',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='认证注册风控配置';
|
||||
|
||||
INSERT INTO auth_risk_configs (app_code, max_accounts_per_device, updated_by_admin_id, created_at_ms, updated_at_ms)
|
||||
SELECT app_code, 1, 0, 0, 0
|
||||
FROM apps
|
||||
ON DUPLICATE KEY UPDATE
|
||||
max_accounts_per_device = max_accounts_per_device;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS users (
|
||||
app_code VARCHAR(32) NOT NULL DEFAULT 'lalu' COMMENT '应用编码,用于多租户隔离',
|
||||
user_id BIGINT NOT NULL PRIMARY KEY COMMENT '用户 ID',
|
||||
@ -68,7 +82,7 @@ CREATE TABLE IF NOT EXISTS users (
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms',
|
||||
UNIQUE KEY uk_users_default_display_user_id (app_code, default_display_user_id),
|
||||
UNIQUE KEY uk_users_current_display_user_id (app_code, current_display_user_id),
|
||||
UNIQUE KEY uk_users_register_device_id (app_code, register_device_id),
|
||||
KEY idx_users_register_device_id (app_code, register_device_id),
|
||||
KEY idx_users_status (app_code, status),
|
||||
KEY idx_users_region_status (app_code, region_id, status),
|
||||
KEY idx_users_country_region (app_code, country, region_id)
|
||||
|
||||
@ -0,0 +1,46 @@
|
||||
CREATE TABLE IF NOT EXISTS auth_risk_configs (
|
||||
app_code VARCHAR(32) NOT NULL PRIMARY KEY COMMENT '应用编码,用于多租户隔离',
|
||||
max_accounts_per_device INT NOT NULL DEFAULT 1 COMMENT '单设备最大注册账号数',
|
||||
updated_by_admin_id BIGINT NOT NULL DEFAULT 0 COMMENT '最近修改后台管理员 ID',
|
||||
created_at_ms BIGINT NOT NULL COMMENT '创建时间,UTC epoch ms',
|
||||
updated_at_ms BIGINT NOT NULL COMMENT '更新时间,UTC epoch ms'
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='认证注册风控配置';
|
||||
|
||||
INSERT INTO auth_risk_configs (app_code, max_accounts_per_device, updated_by_admin_id, created_at_ms, updated_at_ms)
|
||||
SELECT app_code, 1, 0, CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED), CAST(UNIX_TIMESTAMP(UTC_TIMESTAMP(3)) * 1000 AS UNSIGNED)
|
||||
FROM apps
|
||||
ON DUPLICATE KEY UPDATE
|
||||
max_accounts_per_device = max_accounts_per_device;
|
||||
|
||||
SET @drop_unique_register_device_id := (
|
||||
SELECT IF(
|
||||
COUNT(*) > 0,
|
||||
'ALTER TABLE users DROP INDEX uk_users_register_device_id',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'users'
|
||||
AND INDEX_NAME = 'uk_users_register_device_id'
|
||||
AND NON_UNIQUE = 0
|
||||
);
|
||||
|
||||
PREPARE stmt FROM @drop_unique_register_device_id;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
SET @add_register_device_id_index := (
|
||||
SELECT IF(
|
||||
COUNT(*) = 0,
|
||||
'ALTER TABLE users ADD INDEX idx_users_register_device_id (app_code, register_device_id)',
|
||||
'SELECT 1'
|
||||
)
|
||||
FROM information_schema.STATISTICS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'users'
|
||||
AND INDEX_NAME = 'idx_users_register_device_id'
|
||||
);
|
||||
|
||||
PREPARE stmt FROM @add_register_device_id_index;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
@ -135,11 +135,14 @@ func New(cfg config.Config) (*App, error) {
|
||||
micTimeRepo := mysqlRepo.MicTimeRepository()
|
||||
cpRepo := mysqlRepo.CPRepository()
|
||||
var ipDecisionCache authservice.IPDecisionCache
|
||||
var registerRiskConfigCache authservice.RegisterRiskConfigCache
|
||||
var loginRiskRedisClose func() error
|
||||
if cfg.LoginRisk.Enabled && cfg.LoginRisk.RedisAddr != "" {
|
||||
redisClient, redisErr := authservice.NewLoginRiskRedisClient(startupCtx, cfg.LoginRisk.RedisAddr, cfg.LoginRisk.RedisPassword, cfg.LoginRisk.RedisDB)
|
||||
if redisErr == nil {
|
||||
ipDecisionCache = authservice.NewRedisIPDecisionCache(redisClient)
|
||||
riskCache := authservice.NewRedisIPDecisionCache(redisClient)
|
||||
ipDecisionCache = riskCache
|
||||
registerRiskConfigCache = riskCache
|
||||
loginRiskRedisClose = redisClient.Close
|
||||
} else {
|
||||
// IP 风控 Redis 缓存按文档 fail-open;启动继续,worker 仍会写 MySQL 审计。
|
||||
@ -281,6 +284,7 @@ func New(cfg config.Config) (*App, error) {
|
||||
DenylistTTL: time.Duration(cfg.JWT.AccessTokenTTLSec+60) * time.Second,
|
||||
}),
|
||||
authservice.WithIPDecisionCache(ipDecisionCache),
|
||||
authservice.WithRegisterRiskConfigCache(registerRiskConfigCache),
|
||||
authservice.WithIPGeoProviders(authservice.BuildIPGeoProviders(cfg.LoginRisk.Providers)),
|
||||
authservice.WithRegistrationRewardIssuer(registrationRewardIssuer),
|
||||
authservice.WithRegistrationLevelBadgeIssuer(registrationLevelBadgeIssuer),
|
||||
|
||||
@ -82,3 +82,13 @@ type LoginRiskIPWhitelist struct {
|
||||
CreatedAtMs int64
|
||||
UpdatedAtMs int64
|
||||
}
|
||||
|
||||
// RegisterRiskConfig 是注册链路的风控开关集合。
|
||||
// 当前只包含单设备最大账号数,后续增加注册频率或设备指纹策略时仍可复用同一行 App 配置。
|
||||
type RegisterRiskConfig struct {
|
||||
AppCode string
|
||||
MaxAccountsPerDevice int32
|
||||
UpdatedByAdminID int64
|
||||
CreatedAtMs int64
|
||||
UpdatedAtMs int64
|
||||
}
|
||||
|
||||
@ -38,8 +38,12 @@ func (s *Service) QuickCreateAccount(ctx context.Context, password string, regis
|
||||
if s.authRepository == nil {
|
||||
return authdomain.Token{}, xerr.New(xerr.Unavailable, "auth repository is not configured")
|
||||
}
|
||||
maxAccountsPerDevice, err := s.ensureDeviceCanCreatePasswordAccount(ctx, registration, meta)
|
||||
if err != nil {
|
||||
return authdomain.Token{}, err
|
||||
}
|
||||
|
||||
registration, err := s.resolveRegistrationCountry(ctx, registration)
|
||||
registration, err = s.resolveRegistrationCountry(ctx, registration)
|
||||
if err != nil {
|
||||
return authdomain.Token{}, err
|
||||
}
|
||||
@ -98,7 +102,7 @@ func (s *Service) QuickCreateAccount(ctx context.Context, password string, regis
|
||||
RequestID: meta.RequestID,
|
||||
BoundAtMs: user.CreatedAtMs,
|
||||
}
|
||||
err = s.authRepository.CreatePasswordUser(ctx, user, displayIdentity, account, session, inviteBind)
|
||||
err = s.authRepository.CreatePasswordUser(ctx, user, displayIdentity, account, session, inviteBind, maxAccountsPerDevice)
|
||||
if err == nil {
|
||||
if isGameRobot {
|
||||
// 全站机器人账号是后台运营资产,不是 App 登录主体;创建成功后不给 access/refresh token,
|
||||
@ -138,3 +142,21 @@ func (s *Service) QuickCreateAccount(ctx context.Context, password string, regis
|
||||
}
|
||||
return authdomain.Token{}, xerr.New(xerr.DisplayUserIDAllocateFailed, "display_user_id allocation failed")
|
||||
}
|
||||
|
||||
func (s *Service) ensureDeviceCanCreatePasswordAccount(ctx context.Context, registration authdomain.ThirdPartyRegistration, meta Meta) (int32, error) {
|
||||
config, err := s.GetRegisterRiskConfig(ctx)
|
||||
if err != nil {
|
||||
s.audit(ctx, meta, 0, loginPassword, "", resultFailed, string(xerr.CodeOf(err)))
|
||||
return 0, err
|
||||
}
|
||||
count, err := s.authRepository.CountUsersByRegisterDeviceID(ctx, registration.AppCode, registration.DeviceID)
|
||||
if err != nil {
|
||||
s.audit(ctx, meta, 0, loginPassword, "", resultFailed, string(xerr.CodeOf(err)))
|
||||
return 0, err
|
||||
}
|
||||
if count < int64(config.MaxAccountsPerDevice) {
|
||||
return config.MaxAccountsPerDevice, nil
|
||||
}
|
||||
s.audit(ctx, meta, 0, loginPassword, "", resultFailed, string(xerr.DeviceAlreadyRegistered))
|
||||
return 0, xerr.New(xerr.DeviceAlreadyRegistered, "device already registered")
|
||||
}
|
||||
|
||||
@ -0,0 +1,95 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/xerr"
|
||||
authdomain "hyapp/services/user-service/internal/domain/auth"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultMaxAccountsPerDevice = int32(1)
|
||||
registerRiskConfigCacheTTL = 5 * time.Minute
|
||||
)
|
||||
|
||||
// GetRegisterRiskConfig 返回当前 App 的注册风控配置。
|
||||
// Redis 只缓存 5 分钟以降低登录注册热路径回源;缓存异常不阻断读取,避免缓存故障改变注册策略。
|
||||
func (s *Service) GetRegisterRiskConfig(ctx context.Context) (authdomain.RegisterRiskConfig, error) {
|
||||
appCode := appcode.FromContext(ctx)
|
||||
if s.registerRiskConfigCache != nil {
|
||||
config, ok, err := s.registerRiskConfigCache.GetRegisterRiskConfig(ctx, appCode)
|
||||
if err == nil && ok {
|
||||
return normalizeRegisterRiskConfig(config), nil
|
||||
}
|
||||
}
|
||||
config, err := s.loadRegisterRiskConfig(ctx, appCode)
|
||||
if err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, err
|
||||
}
|
||||
if s.registerRiskConfigCache != nil {
|
||||
// 读路径写缓存是加速动作;失败时仍返回 MySQL 事实,后续请求会继续尝试刷新缓存。
|
||||
_ = s.registerRiskConfigCache.SetRegisterRiskConfig(ctx, config, registerRiskConfigCacheTTL)
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// UpdateRegisterRiskConfig 保存注册风控配置并立即刷新 Redis。
|
||||
// MySQL 是持久事实,Redis 是注册热路径缓存;更新后同步刷新同一个 key,避免运营保存后继续命中旧值。
|
||||
func (s *Service) UpdateRegisterRiskConfig(ctx context.Context, maxAccountsPerDevice int32, operatorAdminID int64) (authdomain.RegisterRiskConfig, error) {
|
||||
if maxAccountsPerDevice < 1 {
|
||||
return authdomain.RegisterRiskConfig{}, xerr.New(xerr.InvalidArgument, "max_accounts_per_device must be greater than 0")
|
||||
}
|
||||
if s.authRepository == nil {
|
||||
return authdomain.RegisterRiskConfig{}, xerr.New(xerr.Unavailable, "auth repository is not configured")
|
||||
}
|
||||
nowMs := s.now().UTC().UnixMilli()
|
||||
config, err := s.authRepository.UpsertRegisterRiskConfig(ctx, authdomain.RegisterRiskConfig{
|
||||
AppCode: appcode.FromContext(ctx),
|
||||
MaxAccountsPerDevice: maxAccountsPerDevice,
|
||||
UpdatedByAdminID: operatorAdminID,
|
||||
CreatedAtMs: nowMs,
|
||||
UpdatedAtMs: nowMs,
|
||||
})
|
||||
if err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, err
|
||||
}
|
||||
config = normalizeRegisterRiskConfig(config)
|
||||
if s.registerRiskConfigCache != nil {
|
||||
if err := s.registerRiskConfigCache.SetRegisterRiskConfig(ctx, config, registerRiskConfigCacheTTL); err != nil {
|
||||
// 保存成功但缓存未刷新时返回错误,提示后台重试;否则注册链路可能在 5 分钟内继续读取旧配置。
|
||||
return authdomain.RegisterRiskConfig{}, err
|
||||
}
|
||||
}
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (s *Service) loadRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, error) {
|
||||
if s.authRepository == nil {
|
||||
return defaultRegisterRiskConfig(appCode), nil
|
||||
}
|
||||
config, err := s.authRepository.GetRegisterRiskConfig(ctx, appCode)
|
||||
if xerr.IsCode(err, xerr.NotFound) {
|
||||
return defaultRegisterRiskConfig(appCode), nil
|
||||
}
|
||||
if err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, err
|
||||
}
|
||||
return normalizeRegisterRiskConfig(config), nil
|
||||
}
|
||||
|
||||
func defaultRegisterRiskConfig(appCode string) authdomain.RegisterRiskConfig {
|
||||
return authdomain.RegisterRiskConfig{
|
||||
AppCode: appcode.Normalize(appCode),
|
||||
MaxAccountsPerDevice: defaultMaxAccountsPerDevice,
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeRegisterRiskConfig(config authdomain.RegisterRiskConfig) authdomain.RegisterRiskConfig {
|
||||
config.AppCode = appcode.Normalize(config.AppCode)
|
||||
if config.MaxAccountsPerDevice < 1 {
|
||||
config.MaxAccountsPerDevice = defaultMaxAccountsPerDevice
|
||||
}
|
||||
return config
|
||||
}
|
||||
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/redis/go-redis/v9"
|
||||
"hyapp/pkg/appcode"
|
||||
authdomain "hyapp/services/user-service/internal/domain/auth"
|
||||
)
|
||||
|
||||
type RedisIPDecisionCache struct {
|
||||
@ -82,6 +83,29 @@ func (c *RedisIPDecisionCache) SetIPWhitelist(ctx context.Context, appCode strin
|
||||
return c.client.Set(ctx, loginRiskIPWhitelistKey(appCode), raw, ttl).Err()
|
||||
}
|
||||
|
||||
func (c *RedisIPDecisionCache) GetRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, bool, error) {
|
||||
raw, err := c.client.Get(ctx, registerRiskConfigKey(appCode)).Result()
|
||||
if errors.Is(err, redis.Nil) {
|
||||
return authdomain.RegisterRiskConfig{}, false, nil
|
||||
}
|
||||
if err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, false, err
|
||||
}
|
||||
var config authdomain.RegisterRiskConfig
|
||||
if err := json.Unmarshal([]byte(raw), &config); err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, false, err
|
||||
}
|
||||
return config, true, nil
|
||||
}
|
||||
|
||||
func (c *RedisIPDecisionCache) SetRegisterRiskConfig(ctx context.Context, config authdomain.RegisterRiskConfig, ttl time.Duration) error {
|
||||
raw, err := json.Marshal(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.client.Set(ctx, registerRiskConfigKey(config.AppCode), raw, ttl).Err()
|
||||
}
|
||||
|
||||
func loginRiskIPDecisionKey(appCode string, clientIPHash string) string {
|
||||
return "login_risk:ip:" + appcode.Normalize(appCode) + ":" + strings.TrimSpace(clientIPHash)
|
||||
}
|
||||
@ -93,3 +117,7 @@ func loginRiskIPWhitelistKey(appCode string) string {
|
||||
func revokedSessionKey(appCode string, sessionID string) string {
|
||||
return "auth:revoked_session:" + appcode.Normalize(appCode) + ":" + strings.TrimSpace(sessionID)
|
||||
}
|
||||
|
||||
func registerRiskConfigKey(appCode string) string {
|
||||
return "auth:risk_config:register:" + appcode.Normalize(appCode)
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ type AuthRepository interface {
|
||||
// SetPassword 为已有用户首次写入密码身份。
|
||||
SetPassword(ctx context.Context, account authdomain.PasswordAccount) error
|
||||
// CreatePasswordUser 原子创建用户、默认短号、密码身份和可选首个 session;全站机器人会传空 session。
|
||||
CreatePasswordUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, account authdomain.PasswordAccount, session authdomain.Session, invite invitedomain.BindCommand) error
|
||||
CreatePasswordUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, account authdomain.PasswordAccount, session authdomain.Session, invite invitedomain.BindCommand, maxAccountsPerDevice int32) error
|
||||
// FindPasswordByDisplayUserID 通过当前 active 展示号或 held 默认短号登录别名读取密码身份。
|
||||
FindPasswordByDisplayUserID(ctx context.Context, displayUserID string, nowMs int64) (authdomain.PasswordAccount, error)
|
||||
// CreateSession 创建新的 refresh session。
|
||||
@ -62,10 +62,14 @@ type AuthRepository interface {
|
||||
UpdateSessionHeartbeat(ctx context.Context, sessionID string, userID int64, heartbeatAtMs int64, requestID string) (authdomain.Session, error)
|
||||
// FindThirdPartyIdentity 查找 provider + subject 的绑定。
|
||||
FindThirdPartyIdentity(ctx context.Context, provider string, providerSubject string) (authdomain.ThirdPartyIdentity, error)
|
||||
// FindUserIDByRegisterDeviceID 查找当前 App 下已经占用注册设备号的用户。
|
||||
FindUserIDByRegisterDeviceID(ctx context.Context, appCode string, deviceID string) (int64, error)
|
||||
// CountUsersByRegisterDeviceID 统计当前 App 下已使用同一注册设备号的账号数量。
|
||||
CountUsersByRegisterDeviceID(ctx context.Context, appCode string, deviceID string) (int64, error)
|
||||
// CreateThirdPartyUser 原子创建用户、默认短号、三方身份和首个 session。
|
||||
CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, invite invitedomain.BindCommand) error
|
||||
CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, invite invitedomain.BindCommand, maxAccountsPerDevice int32) error
|
||||
// GetRegisterRiskConfig 读取当前 App 的注册风控配置。
|
||||
GetRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, error)
|
||||
// UpsertRegisterRiskConfig 保存当前 App 的注册风控配置。
|
||||
UpsertRegisterRiskConfig(ctx context.Context, config authdomain.RegisterRiskConfig) (authdomain.RegisterRiskConfig, error)
|
||||
// RecordLoginAudit 记录登录审计,主链路不会因为审计失败而失败。
|
||||
RecordLoginAudit(ctx context.Context, audit authdomain.LoginAudit) error
|
||||
// CreateLoginIPRiskJob 创建登录后异步 IP 风控任务,失败只影响复核能力。
|
||||
@ -171,6 +175,13 @@ type IPDecisionCache interface {
|
||||
SetIPWhitelist(ctx context.Context, appCode string, ips []string, ttl time.Duration) error
|
||||
}
|
||||
|
||||
// RegisterRiskConfigCache 是注册风控配置的 Redis 快取边界。
|
||||
// 该缓存只做读放大优化,MySQL 仍是配置的持久事实来源。
|
||||
type RegisterRiskConfigCache interface {
|
||||
GetRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, bool, error)
|
||||
SetRegisterRiskConfig(ctx context.Context, config authdomain.RegisterRiskConfig, ttl time.Duration) error
|
||||
}
|
||||
|
||||
// IPDecision 是 Redis 中 IP 决策 JSON 的领域投影。
|
||||
type IPDecision struct {
|
||||
Decision string `json:"decision"`
|
||||
@ -218,6 +229,8 @@ type Service struct {
|
||||
loginRiskPolicy LoginRiskPolicy
|
||||
// ipDecisionCache 读写 Redis IP 决策和 session denylist,nil 时按 fail-open 处理。
|
||||
ipDecisionCache IPDecisionCache
|
||||
// registerRiskConfigCache 缓存注册风控配置,后台修改后会立即刷新同一个 Redis key。
|
||||
registerRiskConfigCache RegisterRiskConfigCache
|
||||
// ipGeoProviders 按顺序提供 IP 国家解析能力。
|
||||
ipGeoProviders []IPGeoProvider
|
||||
// registrationRewardIssuer 在注册事务提交后异步式触发奖励;失败只记录日志,不回滚用户注册。
|
||||
@ -292,6 +305,12 @@ func WithIPDecisionCache(cache IPDecisionCache) Option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithRegisterRiskConfigCache(cache RegisterRiskConfigCache) Option {
|
||||
return func(s *Service) {
|
||||
s.registerRiskConfigCache = cache
|
||||
}
|
||||
}
|
||||
|
||||
func WithIPGeoProviders(providers []IPGeoProvider) Option {
|
||||
return func(s *Service) {
|
||||
s.ipGeoProviders = providers
|
||||
|
||||
@ -83,7 +83,8 @@ func (s *Service) LoginThirdParty(ctx context.Context, provider string, credenti
|
||||
s.audit(ctx, meta, 0, loginThird, provider, resultFailed, string(xerr.CodeOf(err)))
|
||||
return authdomain.Token{}, false, err
|
||||
}
|
||||
if err := s.ensureDeviceCanRegisterThirdParty(ctx, registration, meta, provider); err != nil {
|
||||
maxAccountsPerDevice, err := s.ensureDeviceCanRegisterThirdParty(ctx, registration, meta, provider)
|
||||
if err != nil {
|
||||
return authdomain.Token{}, false, err
|
||||
}
|
||||
registration, err = s.resolveRegistrationCountry(ctx, registration)
|
||||
@ -91,24 +92,29 @@ func (s *Service) LoginThirdParty(ctx context.Context, provider string, credenti
|
||||
return authdomain.Token{}, false, err
|
||||
}
|
||||
|
||||
return s.createThirdPartyUser(ctx, provider, profile, registration, meta)
|
||||
return s.createThirdPartyUser(ctx, provider, profile, registration, meta, maxAccountsPerDevice)
|
||||
}
|
||||
|
||||
func (s *Service) ensureDeviceCanRegisterThirdParty(ctx context.Context, registration authdomain.ThirdPartyRegistration, meta Meta, provider string) error {
|
||||
func (s *Service) ensureDeviceCanRegisterThirdParty(ctx context.Context, registration authdomain.ThirdPartyRegistration, meta Meta, provider string) (int32, error) {
|
||||
// 设备号限制只约束“创建新账号”路径;已绑定三方身份登录不经过这里,避免把正常跨设备登录误拦。
|
||||
userID, err := s.authRepository.FindUserIDByRegisterDeviceID(ctx, registration.AppCode, registration.DeviceID)
|
||||
if xerr.IsCode(err, xerr.NotFound) {
|
||||
return nil
|
||||
config, err := s.GetRegisterRiskConfig(ctx)
|
||||
if err != nil {
|
||||
s.audit(ctx, meta, 0, loginThird, provider, resultFailed, string(xerr.CodeOf(err)))
|
||||
return 0, err
|
||||
}
|
||||
count, err := s.authRepository.CountUsersByRegisterDeviceID(ctx, registration.AppCode, registration.DeviceID)
|
||||
if err != nil {
|
||||
// 设备查重失败不能退化为注册,否则并发和依赖异常都会突破一机一号约束。
|
||||
s.audit(ctx, meta, 0, loginThird, provider, resultFailed, string(xerr.CodeOf(err)))
|
||||
return err
|
||||
return 0, err
|
||||
}
|
||||
if count < int64(config.MaxAccountsPerDevice) {
|
||||
return config.MaxAccountsPerDevice, nil
|
||||
}
|
||||
|
||||
// 已有任意用户占用该注册设备时拒绝创建新账号;不返回 user_id,避免客户端枚举设备归属。
|
||||
s.audit(ctx, meta, userID, loginThird, provider, resultFailed, string(xerr.DeviceAlreadyRegistered))
|
||||
return xerr.New(xerr.DeviceAlreadyRegistered, "device already registered")
|
||||
// 已达到配置上限时拒绝创建新账号;审计不写已有 user_id,避免客户端枚举设备归属。
|
||||
s.audit(ctx, meta, 0, loginThird, provider, resultFailed, string(xerr.DeviceAlreadyRegistered))
|
||||
return 0, xerr.New(xerr.DeviceAlreadyRegistered, "device already registered")
|
||||
}
|
||||
|
||||
func (s *Service) loginExistingThirdParty(ctx context.Context, identity authdomain.ThirdPartyIdentity, registration authdomain.ThirdPartyRegistration, meta Meta) (authdomain.Token, bool, error) {
|
||||
@ -143,7 +149,7 @@ func (s *Service) loginExistingThirdParty(ctx context.Context, identity authdoma
|
||||
return token, false, nil
|
||||
}
|
||||
|
||||
func (s *Service) createThirdPartyUser(ctx context.Context, provider string, profile authdomain.ThirdPartyProfile, registration authdomain.ThirdPartyRegistration, meta Meta) (authdomain.Token, bool, error) {
|
||||
func (s *Service) createThirdPartyUser(ctx context.Context, provider string, profile authdomain.ThirdPartyProfile, registration authdomain.ThirdPartyRegistration, meta Meta, maxAccountsPerDevice int32) (authdomain.Token, bool, error) {
|
||||
var lastErr error
|
||||
for attempt := 0; attempt < s.allocateMaxAttempts; attempt++ {
|
||||
// 三方首次登录要同时生成 user_id 和默认短号,短号冲突时有限重试。
|
||||
@ -186,7 +192,7 @@ func (s *Service) createThirdPartyUser(ctx context.Context, provider string, pro
|
||||
RequestID: meta.RequestID,
|
||||
BoundAtMs: user.CreatedAtMs,
|
||||
}
|
||||
err = s.authRepository.CreateThirdPartyUser(ctx, user, displayIdentity, thirdParty, session, inviteBind)
|
||||
err = s.authRepository.CreateThirdPartyUser(ctx, user, displayIdentity, thirdParty, session, inviteBind, maxAccountsPerDevice)
|
||||
if err == nil {
|
||||
// repository 事务成功后,用户、默认短号、三方绑定和首个 session 同时存在。
|
||||
s.audit(ctx, meta, user.UserID, loginThird, provider, resultSuccess, "")
|
||||
|
||||
@ -29,7 +29,7 @@ func (r *Repository) SetPassword(ctx context.Context, account authdomain.Passwor
|
||||
}
|
||||
|
||||
// CreatePasswordUser 原子创建完整密码账号,服务快捷建号和联调账号准备。
|
||||
func (r *Repository) CreatePasswordUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, account authdomain.PasswordAccount, session authdomain.Session, inviteBind invitedomain.BindCommand) error {
|
||||
func (r *Repository) CreatePasswordUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, account authdomain.PasswordAccount, session authdomain.Session, inviteBind invitedomain.BindCommand, maxAccountsPerDevice int32) error {
|
||||
// 普通快捷账号必须和 refresh session 同事务提交,避免返回不可登录的 uid;
|
||||
// 全站机器人会传入空 session,只写资料和密码身份,不产生任何可续期登录态。
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
@ -38,6 +38,10 @@ func (r *Repository) CreatePasswordUser(ctx context.Context, user userdomain.Use
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if err := ensureRegisterDeviceQuotaTx(ctx, tx, user.AppCode, user.RegisterDeviceID, maxAccountsPerDevice); err != nil {
|
||||
// 快捷建号也写 users.register_device_id;事务内锁定同设备行,避免绕过注册风控上限。
|
||||
return err
|
||||
}
|
||||
if err := userstorage.InsertUserIdentity(ctx, tx, user, identity); err != nil {
|
||||
// 默认短号唯一键冲突交给 service 使用新 user_id/display_user_id 重试。
|
||||
return mapAuthDuplicateError(err)
|
||||
|
||||
@ -0,0 +1,82 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"strings"
|
||||
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/xerr"
|
||||
authdomain "hyapp/services/user-service/internal/domain/auth"
|
||||
)
|
||||
|
||||
func (r *Repository) GetRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, error) {
|
||||
var config authdomain.RegisterRiskConfig
|
||||
err := r.db.QueryRowContext(ctx, `
|
||||
SELECT app_code, max_accounts_per_device, updated_by_admin_id, created_at_ms, updated_at_ms
|
||||
FROM auth_risk_configs
|
||||
WHERE app_code = ?
|
||||
`, appcode.Normalize(appCode)).Scan(&config.AppCode, &config.MaxAccountsPerDevice, &config.UpdatedByAdminID, &config.CreatedAtMs, &config.UpdatedAtMs)
|
||||
if err == sql.ErrNoRows {
|
||||
return authdomain.RegisterRiskConfig{}, xerr.New(xerr.NotFound, "register risk config not found")
|
||||
}
|
||||
if err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
func (r *Repository) UpsertRegisterRiskConfig(ctx context.Context, config authdomain.RegisterRiskConfig) (authdomain.RegisterRiskConfig, error) {
|
||||
appCode := appcode.Normalize(config.AppCode)
|
||||
if config.MaxAccountsPerDevice < 1 {
|
||||
return authdomain.RegisterRiskConfig{}, xerr.New(xerr.InvalidArgument, "max_accounts_per_device must be greater than 0")
|
||||
}
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO auth_risk_configs (
|
||||
app_code, max_accounts_per_device, updated_by_admin_id, created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
max_accounts_per_device = VALUES(max_accounts_per_device),
|
||||
updated_by_admin_id = VALUES(updated_by_admin_id),
|
||||
updated_at_ms = VALUES(updated_at_ms)
|
||||
`, appCode, config.MaxAccountsPerDevice, config.UpdatedByAdminID, config.CreatedAtMs, config.UpdatedAtMs)
|
||||
if err != nil {
|
||||
return authdomain.RegisterRiskConfig{}, err
|
||||
}
|
||||
return r.GetRegisterRiskConfig(ctx, appCode)
|
||||
}
|
||||
|
||||
func ensureRegisterDeviceQuotaTx(ctx context.Context, tx *sql.Tx, appCode string, deviceID string, maxAccountsPerDevice int32) error {
|
||||
appCode = appcode.Normalize(appCode)
|
||||
deviceID = strings.TrimSpace(deviceID)
|
||||
if deviceID == "" {
|
||||
return nil
|
||||
}
|
||||
if maxAccountsPerDevice < 1 {
|
||||
maxAccountsPerDevice = 1
|
||||
}
|
||||
rows, err := tx.QueryContext(ctx, `
|
||||
SELECT user_id
|
||||
FROM users
|
||||
WHERE app_code = ? AND register_device_id = ?
|
||||
FOR UPDATE
|
||||
`, appCode, deviceID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var count int32
|
||||
for rows.Next() {
|
||||
// FOR UPDATE 锁住同设备的已有用户行;读完后再判断,确保等待中的并发事务能看到最新提交结果。
|
||||
count++
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
if count >= maxAccountsPerDevice {
|
||||
return xerr.New(xerr.DeviceAlreadyRegistered, "device already registered")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -51,9 +51,22 @@ func (r *Repository) FindUserIDByRegisterDeviceID(ctx context.Context, appCode s
|
||||
return userID, nil
|
||||
}
|
||||
|
||||
func (r *Repository) CountUsersByRegisterDeviceID(ctx context.Context, appCode string, deviceID string) (int64, error) {
|
||||
var count int64
|
||||
if err := r.db.QueryRowContext(ctx, `
|
||||
SELECT COUNT(*)
|
||||
FROM users
|
||||
WHERE app_code = ? AND register_device_id = ?
|
||||
`, appcode.Normalize(appCode), deviceID).Scan(&count); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return count, nil
|
||||
}
|
||||
|
||||
// CreateThirdPartyUser 原子创建用户、默认短号、三方身份和首个 session。
|
||||
|
||||
func (r *Repository) CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, inviteBind invitedomain.BindCommand) error {
|
||||
func (r *Repository) CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, inviteBind invitedomain.BindCommand, maxAccountsPerDevice int32) error {
|
||||
// 三方首次登录注册必须同时写用户、默认短号、三方绑定和首个 session。
|
||||
tx, err := r.db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
@ -61,6 +74,10 @@ func (r *Repository) CreateThirdPartyUser(ctx context.Context, user userdomain.U
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if err := ensureRegisterDeviceQuotaTx(ctx, tx, user.AppCode, user.RegisterDeviceID, maxAccountsPerDevice); err != nil {
|
||||
// 事务内再次校验设备上限,避免两个并发注册都在事务外读到旧计数后同时插入。
|
||||
return err
|
||||
}
|
||||
if err := userstorage.InsertUserIdentity(ctx, tx, user, identity); err != nil {
|
||||
// 默认短号冲突由 service 重试。
|
||||
return mapAuthDuplicateError(err)
|
||||
|
||||
@ -300,8 +300,8 @@ func (r *Repository) SetPassword(ctx context.Context, account authdomain.Passwor
|
||||
}
|
||||
|
||||
// CreatePasswordUser 让测试 wrapper 继续满足认证接口。
|
||||
func (r *Repository) CreatePasswordUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, account authdomain.PasswordAccount, session authdomain.Session, invite invitedomain.BindCommand) error {
|
||||
return r.Repository.AuthRepository().CreatePasswordUser(ctx, user, identity, account, session, invite)
|
||||
func (r *Repository) CreatePasswordUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, account authdomain.PasswordAccount, session authdomain.Session, invite invitedomain.BindCommand, maxAccountsPerDevice int32) error {
|
||||
return r.Repository.AuthRepository().CreatePasswordUser(ctx, user, identity, account, session, invite, maxAccountsPerDevice)
|
||||
}
|
||||
|
||||
// FindPasswordByDisplayUserID 让测试 wrapper 继续满足认证接口。
|
||||
@ -354,14 +354,24 @@ func (r *Repository) FindThirdPartyIdentity(ctx context.Context, provider string
|
||||
return r.Repository.AuthRepository().FindThirdPartyIdentity(ctx, provider, providerSubject)
|
||||
}
|
||||
|
||||
// FindUserIDByRegisterDeviceID 让测试 wrapper 继续满足认证接口。
|
||||
func (r *Repository) FindUserIDByRegisterDeviceID(ctx context.Context, appCode string, deviceID string) (int64, error) {
|
||||
return r.Repository.AuthRepository().FindUserIDByRegisterDeviceID(ctx, appCode, deviceID)
|
||||
// CountUsersByRegisterDeviceID 让测试 wrapper 继续满足认证接口。
|
||||
func (r *Repository) CountUsersByRegisterDeviceID(ctx context.Context, appCode string, deviceID string) (int64, error) {
|
||||
return r.Repository.AuthRepository().CountUsersByRegisterDeviceID(ctx, appCode, deviceID)
|
||||
}
|
||||
|
||||
// CreateThirdPartyUser 让测试 wrapper 继续满足认证接口。
|
||||
func (r *Repository) CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, invite invitedomain.BindCommand) error {
|
||||
return r.Repository.AuthRepository().CreateThirdPartyUser(ctx, user, identity, thirdParty, session, invite)
|
||||
func (r *Repository) CreateThirdPartyUser(ctx context.Context, user userdomain.User, identity userdomain.Identity, thirdParty authdomain.ThirdPartyIdentity, session authdomain.Session, invite invitedomain.BindCommand, maxAccountsPerDevice int32) error {
|
||||
return r.Repository.AuthRepository().CreateThirdPartyUser(ctx, user, identity, thirdParty, session, invite, maxAccountsPerDevice)
|
||||
}
|
||||
|
||||
// GetRegisterRiskConfig 让测试 wrapper 继续满足认证接口。
|
||||
func (r *Repository) GetRegisterRiskConfig(ctx context.Context, appCode string) (authdomain.RegisterRiskConfig, error) {
|
||||
return r.Repository.AuthRepository().GetRegisterRiskConfig(ctx, appCode)
|
||||
}
|
||||
|
||||
// UpsertRegisterRiskConfig 让测试 wrapper 继续满足认证接口。
|
||||
func (r *Repository) UpsertRegisterRiskConfig(ctx context.Context, config authdomain.RegisterRiskConfig) (authdomain.RegisterRiskConfig, error) {
|
||||
return r.Repository.AuthRepository().UpsertRegisterRiskConfig(ctx, config)
|
||||
}
|
||||
|
||||
// RecordLoginAudit 让测试 wrapper 继续满足认证接口。
|
||||
|
||||
@ -46,6 +46,15 @@ func toProtoToken(token authdomain.Token) *userv1.AuthToken {
|
||||
}
|
||||
}
|
||||
|
||||
func toProtoRegisterRiskConfig(config authdomain.RegisterRiskConfig) *userv1.RegisterRiskConfig {
|
||||
return &userv1.RegisterRiskConfig{
|
||||
AppCode: config.AppCode,
|
||||
MaxAccountsPerDevice: config.MaxAccountsPerDevice,
|
||||
UpdatedAtMs: config.UpdatedAtMs,
|
||||
UpdatedByAdminId: config.UpdatedByAdminID,
|
||||
}
|
||||
}
|
||||
|
||||
// toProtoUser 把领域用户转换为 protobuf 用户投影。
|
||||
func toProtoUser(user userdomain.User) *userv1.User {
|
||||
// User proto 只暴露用户主状态和当前展示短号,不包含密码、三方身份或房间状态。
|
||||
|
||||
@ -222,6 +222,26 @@ func (s *Server) CheckLoginRiskIPWhitelist(ctx context.Context, req *userv1.Chec
|
||||
return &userv1.CheckLoginRiskIPWhitelistResponse{Whitelisted: whitelisted}, nil
|
||||
}
|
||||
|
||||
// GetRegisterRiskConfig 返回后台配置页和注册链路共用的设备注册上限。
|
||||
func (s *Server) GetRegisterRiskConfig(ctx context.Context, req *userv1.GetRegisterRiskConfigRequest) (*userv1.GetRegisterRiskConfigResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
config, err := s.authSvc.GetRegisterRiskConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &userv1.GetRegisterRiskConfigResponse{Config: toProtoRegisterRiskConfig(config)}, nil
|
||||
}
|
||||
|
||||
// UpdateRegisterRiskConfig 保存后台注册风控配置,并由 auth service 刷新 Redis 缓存。
|
||||
func (s *Server) UpdateRegisterRiskConfig(ctx context.Context, req *userv1.UpdateRegisterRiskConfigRequest) (*userv1.UpdateRegisterRiskConfigResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
config, err := s.authSvc.UpdateRegisterRiskConfig(ctx, req.GetMaxAccountsPerDevice(), req.GetOperatorAdminId())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &userv1.UpdateRegisterRiskConfigResponse{Config: toProtoRegisterRiskConfig(config)}, nil
|
||||
}
|
||||
|
||||
// AppHeartbeat 刷新当前 App 登录会话最近在线时间,不创建房间或麦位 presence。
|
||||
func (s *Server) AppHeartbeat(ctx context.Context, req *userv1.AppHeartbeatRequest) (*userv1.AppHeartbeatResponse, error) {
|
||||
ctx = contextWithApp(ctx, req.GetMeta())
|
||||
|
||||
@ -46,6 +46,8 @@ const (
|
||||
RechargeAudienceNormal = "normal"
|
||||
// RechargeAudienceCoinSeller 表示币商可购买的充值档位。
|
||||
RechargeAudienceCoinSeller = "coin_seller"
|
||||
// RechargeAudienceTemporary 表示运营临时收款链接;支付完成后只标记订单 paid,不自动给任何用户入账。
|
||||
RechargeAudienceTemporary = "temporary"
|
||||
// RechargeChannelGoogle 是 android 平台内购渠道标识。
|
||||
RechargeChannelGoogle = "google"
|
||||
// RechargeChannelApple 是 iOS 平台内购渠道标识。
|
||||
@ -70,6 +72,8 @@ const (
|
||||
ExternalRechargeStatusRedirected = "redirected"
|
||||
// ExternalRechargeStatusCredited 表示外部充值已完成钱包入账。
|
||||
ExternalRechargeStatusCredited = "credited"
|
||||
// ExternalRechargeStatusPaid 表示临时外部收款已支付成功,等待运营人工核销金币。
|
||||
ExternalRechargeStatusPaid = "paid"
|
||||
// ExternalRechargeStatusFailed 表示外部充值被验签、金额或链上校验拒绝。
|
||||
ExternalRechargeStatusFailed = "failed"
|
||||
// PaymentStatusCredited 表示支付已完成校验并入账。
|
||||
|
||||
@ -163,6 +163,16 @@ type H5RechargeOptions struct {
|
||||
USDTTRC20Address string
|
||||
}
|
||||
|
||||
// ListTemporaryExternalRechargeOrdersQuery 是后台临时支付链接列表的筛选条件。
|
||||
type ListTemporaryExternalRechargeOrdersQuery struct {
|
||||
AppCode string
|
||||
Status string
|
||||
ProviderCode string
|
||||
Keyword string
|
||||
Page int32
|
||||
PageSize int32
|
||||
}
|
||||
|
||||
// ExternalRechargeOrder 保存 H5 外部充值订单的订单、支付和入账状态。
|
||||
type ExternalRechargeOrder struct {
|
||||
OrderID string
|
||||
@ -216,6 +226,24 @@ type CreateExternalRechargeOrderCommand struct {
|
||||
PayerEmail string
|
||||
}
|
||||
|
||||
// CreateTemporaryExternalRechargeOrderCommand 是运营临时收款链接的下单快照。
|
||||
// 这类订单没有充值目标用户和商品档位,支付成功后只保留 paid 状态,金币由运营线下核销。
|
||||
type CreateTemporaryExternalRechargeOrderCommand struct {
|
||||
AppCode string
|
||||
CommandID string
|
||||
CoinAmount int64
|
||||
USDMinorAmount int64
|
||||
ProviderCode string
|
||||
PaymentMethodID int64
|
||||
ReturnURL string
|
||||
NotifyURL string
|
||||
ClientIP string
|
||||
Language string
|
||||
PayerName string
|
||||
PayerAccount string
|
||||
PayerEmail string
|
||||
}
|
||||
|
||||
type SubmitExternalRechargeTxCommand struct {
|
||||
AppCode string
|
||||
OrderID string
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// HandleMifapayNotify 只在验签、订单号、币种和金额全部匹配后入账;重复回调返回 SUCCESS。
|
||||
// HandleMifapayNotify 只在验签、订单号、币种和金额全部匹配后更新订单;正式订单入账,临时订单只标记 paid。
|
||||
func (s *Service) HandleMifapayNotify(ctx context.Context, appCode string, notification ledger.MifaPayNotification) (ledger.ExternalRechargeOrder, bool, error) {
|
||||
if s.mifaPay == nil {
|
||||
return ledger.ExternalRechargeOrder{}, false, xerr.New(xerr.Unavailable, "mifapay client is not configured")
|
||||
@ -33,11 +33,15 @@ func (s *Service) HandleMifapayNotify(ctx context.Context, appCode string, notif
|
||||
order, err = s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "mifapay callback amount or currency mismatch", data.RawJSON)
|
||||
return order, false, err
|
||||
}
|
||||
if isTemporaryExternalRechargeOrder(order) {
|
||||
paid, err := s.repository.MarkExternalRechargeOrderPaid(ctx, order.AppCode, order.OrderID, data.ProviderOrderID, data.RawJSON)
|
||||
return paid, err == nil, err
|
||||
}
|
||||
credited, err := s.repository.CreditExternalRechargeOrder(ctx, order.AppCode, order.OrderID, data.ProviderOrderID, "", data.RawJSON)
|
||||
return credited, err == nil, err
|
||||
}
|
||||
|
||||
// HandleV5PayNotify 只在验签、订单号、币种、金额和 productType 全部匹配后入账;重复回调返回 success。
|
||||
// HandleV5PayNotify 只在验签、订单号、币种、金额和 productType 全部匹配后更新订单;正式订单入账,临时订单只标记 paid。
|
||||
func (s *Service) HandleV5PayNotify(ctx context.Context, appCode string, notification ledger.V5PayNotification) (ledger.ExternalRechargeOrder, bool, error) {
|
||||
if s.v5Pay == nil {
|
||||
return ledger.ExternalRechargeOrder{}, false, xerr.New(xerr.Unavailable, "v5pay client is not configured")
|
||||
@ -60,6 +64,10 @@ func (s *Service) HandleV5PayNotify(ctx context.Context, appCode string, notific
|
||||
order, err = s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "v5pay callback amount currency or product mismatch", data.RawJSON)
|
||||
return order, false, err
|
||||
}
|
||||
if isTemporaryExternalRechargeOrder(order) {
|
||||
paid, err := s.repository.MarkExternalRechargeOrderPaid(ctx, order.AppCode, order.OrderID, data.ProviderOrderID, data.RawJSON)
|
||||
return paid, err == nil, err
|
||||
}
|
||||
credited, err := s.repository.CreditExternalRechargeOrder(ctx, order.AppCode, order.OrderID, data.ProviderOrderID, "", data.RawJSON)
|
||||
return credited, err == nil, err
|
||||
case "3", "5", "6":
|
||||
|
||||
@ -37,7 +37,7 @@ func (s *Service) ReconcileExternalRechargeOrders(ctx context.Context, appCode s
|
||||
}
|
||||
|
||||
func (s *Service) refreshMifaPayRechargeOrder(ctx context.Context, order ledger.ExternalRechargeOrder) (ledger.ExternalRechargeOrder, error) {
|
||||
if s.mifaPay == nil || order.ProviderCode != ledger.PaymentProviderMifaPay || order.Status == ledger.ExternalRechargeStatusCredited || order.Status == ledger.ExternalRechargeStatusFailed {
|
||||
if s.mifaPay == nil || order.ProviderCode != ledger.PaymentProviderMifaPay || isExternalRechargeTerminalStatus(order.Status) {
|
||||
return order, nil
|
||||
}
|
||||
query, err := s.mifaPay.QueryOrder(ctx, MifaPayQueryOrderRequest{
|
||||
@ -64,6 +64,9 @@ func (s *Service) refreshMifaPayRechargeOrder(ctx context.Context, order ledger.
|
||||
|
||||
return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "mifapay query order data mismatch", query.RawJSON)
|
||||
}
|
||||
if isTemporaryExternalRechargeOrder(order) {
|
||||
return s.repository.MarkExternalRechargeOrderPaid(ctx, order.AppCode, order.OrderID, providerOrderID, query.RawJSON)
|
||||
}
|
||||
return s.repository.CreditExternalRechargeOrder(ctx, order.AppCode, order.OrderID, providerOrderID, "", query.RawJSON)
|
||||
case "4":
|
||||
return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "mifapay order status 4", query.RawJSON)
|
||||
@ -75,7 +78,7 @@ func (s *Service) refreshMifaPayRechargeOrder(ctx context.Context, order ledger.
|
||||
}
|
||||
|
||||
func (s *Service) refreshV5PayRechargeOrder(ctx context.Context, order ledger.ExternalRechargeOrder) (ledger.ExternalRechargeOrder, error) {
|
||||
if s.v5Pay == nil || order.ProviderCode != ledger.PaymentProviderV5Pay || order.Status == ledger.ExternalRechargeStatusCredited || order.Status == ledger.ExternalRechargeStatusFailed {
|
||||
if s.v5Pay == nil || order.ProviderCode != ledger.PaymentProviderV5Pay || isExternalRechargeTerminalStatus(order.Status) {
|
||||
return order, nil
|
||||
}
|
||||
query, err := s.v5Pay.QueryOrder(ctx, V5PayQueryOrderRequest{
|
||||
@ -104,6 +107,9 @@ func (s *Service) refreshV5PayRechargeOrder(ctx context.Context, order ledger.Ex
|
||||
|
||||
return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "v5pay query order data mismatch", query.RawJSON)
|
||||
}
|
||||
if isTemporaryExternalRechargeOrder(order) {
|
||||
return s.repository.MarkExternalRechargeOrderPaid(ctx, order.AppCode, order.OrderID, providerOrderID, query.RawJSON)
|
||||
}
|
||||
return s.repository.CreditExternalRechargeOrder(ctx, order.AppCode, order.OrderID, providerOrderID, "", query.RawJSON)
|
||||
case "3", "5", "6":
|
||||
return s.repository.MarkExternalRechargeOrderFailed(ctx, order.AppCode, order.OrderID, "v5pay order status "+query.Status, query.RawJSON)
|
||||
@ -113,3 +119,12 @@ func (s *Service) refreshV5PayRechargeOrder(ctx context.Context, order ledger.Ex
|
||||
return order, nil
|
||||
}
|
||||
}
|
||||
|
||||
func isExternalRechargeTerminalStatus(status string) bool {
|
||||
switch strings.TrimSpace(status) {
|
||||
case ledger.ExternalRechargeStatusCredited, ledger.ExternalRechargeStatusPaid, ledger.ExternalRechargeStatusFailed:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,225 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hyapp/pkg/appcode"
|
||||
"hyapp/pkg/xerr"
|
||||
"hyapp/services/wallet-service/internal/domain/ledger"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const temporaryProviderMemberID int64 = 1
|
||||
|
||||
// CreateTemporaryRechargeOrder 创建运营临时收款订单;它只校验支付方式和金额,不读取充值商品。
|
||||
func (s *Service) CreateTemporaryRechargeOrder(ctx context.Context, command ledger.CreateTemporaryExternalRechargeOrderCommand) (ledger.ExternalRechargeOrder, error) {
|
||||
command = normalizeCreateTemporaryExternalRechargeOrderCommand(command)
|
||||
if err := validateCreateTemporaryExternalRechargeOrderCommand(command); err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
if s.repository == nil {
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||||
}
|
||||
ctx = appcode.WithContext(ctx, command.AppCode)
|
||||
|
||||
switch command.ProviderCode {
|
||||
case ledger.PaymentProviderMifaPay:
|
||||
return s.createTemporaryMifaPayRechargeOrder(ctx, command)
|
||||
case ledger.PaymentProviderV5Pay:
|
||||
return s.createTemporaryV5PayRechargeOrder(ctx, command)
|
||||
default:
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.InvalidArgument, "payment provider is invalid")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) createTemporaryMifaPayRechargeOrder(ctx context.Context, command ledger.CreateTemporaryExternalRechargeOrderCommand) (ledger.ExternalRechargeOrder, error) {
|
||||
if s.mifaPay == nil {
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "mifapay client is not configured")
|
||||
}
|
||||
method, err := s.repository.GetThirdPartyPaymentMethod(ctx, command.AppCode, command.PaymentMethodID)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
if err := validateMifaPayMethodForTemporaryOrder(method, command); err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
// 临时链接没有商品档位,三方实付金额只能由运营输入的 USD 金额和支付方式汇率即时换算;订单快照会保存换算结果。
|
||||
providerAmountMinor, err := calculateProviderAmountMinor(command.USDMinorAmount, method.USDToCurrencyRate, method.CurrencyCode)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
// 先写 pending 订单再调三方,保证三方回调先于 HTTP 响应返回时也能按 order_id 找到本地订单。
|
||||
order, err := s.repository.CreateTemporaryExternalRechargeOrder(ctx, command, method, providerAmountMinor)
|
||||
if err != nil || order.IdempotentReplay {
|
||||
return order, err
|
||||
}
|
||||
// notify_url 是支付状态闭环的必要条件;缺配置时把订单打失败,避免运营拿到一个无法回调核销的链接。
|
||||
notifyURL := firstNonEmpty(command.NotifyURL, s.externalRecharge.MifaPayNotifyURL)
|
||||
returnURL := firstNonEmpty(command.ReturnURL, s.externalRecharge.MifaPayReturnURL)
|
||||
if notifyURL == "" {
|
||||
_, _ = s.repository.MarkExternalRechargeOrderFailed(ctx, command.AppCode, order.OrderID, "mifapay notify_url is not configured", "")
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "mifapay notify_url is not configured")
|
||||
}
|
||||
resp, err := s.mifaPay.CreateOrder(ctx, MifaPayCreateOrderRequest{
|
||||
OrderID: order.OrderID,
|
||||
TargetUserID: temporaryProviderMemberID,
|
||||
ProductName: order.ProductName,
|
||||
CoinAmount: order.CoinAmount,
|
||||
AmountMinor: order.USDMinorAmount,
|
||||
CurrencyCode: order.CurrencyCode,
|
||||
CountryCode: order.CountryCode,
|
||||
PayWay: order.PayWay,
|
||||
PayType: order.PayType,
|
||||
NotifyURL: notifyURL,
|
||||
ReturnURL: mifaPayProviderReturnURL(returnURL),
|
||||
ClientIP: command.ClientIP,
|
||||
Language: command.Language,
|
||||
ProviderAmountMinor: providerAmountMinor,
|
||||
PayerName: command.PayerName,
|
||||
PayerAccount: command.PayerAccount,
|
||||
PayerEmail: command.PayerEmail,
|
||||
})
|
||||
if err != nil {
|
||||
_, _ = s.repository.MarkExternalRechargeOrderFailed(ctx, command.AppCode, order.OrderID, err.Error(), mifaPayProviderPayloadJSON(err))
|
||||
return ledger.ExternalRechargeOrder{}, normalizeMifaPayOrderError(err)
|
||||
}
|
||||
return s.repository.MarkExternalRechargeOrderRedirected(ctx, command.AppCode, order.OrderID, resp.ProviderOrderID, resp.PayURL, resp.RawJSON)
|
||||
}
|
||||
|
||||
func (s *Service) createTemporaryV5PayRechargeOrder(ctx context.Context, command ledger.CreateTemporaryExternalRechargeOrderCommand) (ledger.ExternalRechargeOrder, error) {
|
||||
if s.v5Pay == nil {
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "v5pay client is not configured")
|
||||
}
|
||||
method, err := s.repository.GetThirdPartyPaymentMethod(ctx, command.AppCode, command.PaymentMethodID)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
if err := validateV5PayMethodForTemporaryOrder(method, command); err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
// V5Pay 同样以支付方式汇率换算本币金额;临时订单不读取 wallet_recharge_products,避免误套正式商品受众。
|
||||
providerAmountMinor, err := calculateProviderAmountMinor(command.USDMinorAmount, method.USDToCurrencyRate, method.CurrencyCode)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
// 本地订单先落库,三方创建失败再转 failed;这样人工排查时能看到每次临时建链尝试。
|
||||
order, err := s.repository.CreateTemporaryExternalRechargeOrder(ctx, command, method, providerAmountMinor)
|
||||
if err != nil || order.IdempotentReplay {
|
||||
return order, err
|
||||
}
|
||||
notifyURL := firstNonEmpty(command.NotifyURL, s.externalRecharge.V5PayNotifyURL)
|
||||
returnURL := firstNonEmpty(command.ReturnURL, s.externalRecharge.V5PayReturnURL)
|
||||
if notifyURL == "" {
|
||||
_, _ = s.repository.MarkExternalRechargeOrderFailed(ctx, command.AppCode, order.OrderID, "v5pay notify_url is not configured", "")
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "v5pay notify_url is not configured")
|
||||
}
|
||||
resp, err := s.v5Pay.CreateOrder(ctx, V5PayCreateOrderRequest{
|
||||
OrderID: order.OrderID,
|
||||
TargetUserID: temporaryProviderMemberID,
|
||||
ProductName: order.ProductName,
|
||||
CoinAmount: order.CoinAmount,
|
||||
AmountMinor: order.USDMinorAmount,
|
||||
CurrencyCode: order.CurrencyCode,
|
||||
CountryCode: order.CountryCode,
|
||||
ProductType: order.PayType,
|
||||
NotifyURL: notifyURL,
|
||||
ReturnURL: v5PayProviderReturnURL(returnURL),
|
||||
Language: command.Language,
|
||||
ProviderAmountMinor: providerAmountMinor,
|
||||
PayerName: command.PayerName,
|
||||
PayerAccount: command.PayerAccount,
|
||||
PayerEmail: command.PayerEmail,
|
||||
})
|
||||
if err != nil {
|
||||
_, _ = s.repository.MarkExternalRechargeOrderFailed(ctx, command.AppCode, order.OrderID, err.Error(), providerPayloadJSON(err))
|
||||
return ledger.ExternalRechargeOrder{}, normalizeExternalProviderOrderError(err, "v5pay")
|
||||
}
|
||||
return s.repository.MarkExternalRechargeOrderRedirected(ctx, command.AppCode, order.OrderID, resp.ProviderOrderID, resp.PayURL, resp.RawJSON)
|
||||
}
|
||||
|
||||
func (s *Service) GetTemporaryRechargeOrder(ctx context.Context, appCode string, orderID string) (ledger.ExternalRechargeOrder, error) {
|
||||
if s.repository == nil {
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||||
}
|
||||
ctx = appcode.WithContext(ctx, appcode.Normalize(appCode))
|
||||
order, err := s.repository.GetExternalRechargeOrder(ctx, appcode.FromContext(ctx), strings.TrimSpace(orderID))
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
if !isTemporaryExternalRechargeOrder(order) {
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.NotFound, "temporary recharge order not found")
|
||||
}
|
||||
// 单笔查询被 H5 验证框和 admin 页面共用;这里主动刷新三方状态,但刷新失败不盖掉本地快照,避免短暂上游错误让后台看不到订单。
|
||||
if refreshed, err := s.refreshMifaPayRechargeOrder(ctx, order); err == nil {
|
||||
order = refreshed
|
||||
}
|
||||
if refreshed, err := s.refreshV5PayRechargeOrder(ctx, order); err == nil {
|
||||
order = refreshed
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (s *Service) ListTemporaryRechargeOrders(ctx context.Context, query ledger.ListTemporaryExternalRechargeOrdersQuery) ([]ledger.ExternalRechargeOrder, int64, error) {
|
||||
if s.repository == nil {
|
||||
return nil, 0, xerr.New(xerr.Unavailable, "wallet repository is not configured")
|
||||
}
|
||||
query.AppCode = appcode.Normalize(query.AppCode)
|
||||
query.ProviderCode = ledger.NormalizePaymentProvider(query.ProviderCode)
|
||||
query.Status = strings.TrimSpace(query.Status)
|
||||
query.Keyword = strings.TrimSpace(query.Keyword)
|
||||
ctx = appcode.WithContext(ctx, query.AppCode)
|
||||
return s.repository.ListTemporaryExternalRechargeOrders(ctx, query)
|
||||
}
|
||||
|
||||
func normalizeCreateTemporaryExternalRechargeOrderCommand(command ledger.CreateTemporaryExternalRechargeOrderCommand) ledger.CreateTemporaryExternalRechargeOrderCommand {
|
||||
command.AppCode = appcode.Normalize(command.AppCode)
|
||||
command.CommandID = strings.TrimSpace(command.CommandID)
|
||||
command.ProviderCode = ledger.NormalizePaymentProvider(command.ProviderCode)
|
||||
command.ReturnURL = strings.TrimSpace(command.ReturnURL)
|
||||
command.NotifyURL = strings.TrimSpace(command.NotifyURL)
|
||||
command.ClientIP = strings.TrimSpace(command.ClientIP)
|
||||
command.Language = normalizeMifaPayLanguage(command.Language)
|
||||
command.PayerName = strings.TrimSpace(command.PayerName)
|
||||
command.PayerAccount = strings.TrimSpace(command.PayerAccount)
|
||||
command.PayerEmail = strings.TrimSpace(command.PayerEmail)
|
||||
return command
|
||||
}
|
||||
|
||||
func validateCreateTemporaryExternalRechargeOrderCommand(command ledger.CreateTemporaryExternalRechargeOrderCommand) error {
|
||||
if command.CommandID == "" || command.CoinAmount <= 0 || command.USDMinorAmount <= 0 || command.PaymentMethodID <= 0 {
|
||||
return xerr.New(xerr.InvalidArgument, "temporary recharge command is incomplete")
|
||||
}
|
||||
if command.ProviderCode == "" {
|
||||
return xerr.New(xerr.InvalidArgument, "temporary recharge provider is invalid")
|
||||
}
|
||||
if len(command.CommandID) > 128 {
|
||||
return xerr.New(xerr.InvalidArgument, "command_id is too long")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateMifaPayMethodForTemporaryOrder(method ledger.ThirdPartyPaymentMethod, command ledger.CreateTemporaryExternalRechargeOrderCommand) error {
|
||||
if method.ProviderCode != ledger.PaymentProviderMifaPay || method.Status != ledger.ThirdPartyPaymentStatusActive || method.MethodID != command.PaymentMethodID {
|
||||
return xerr.New(xerr.Conflict, "mifapay method is not active")
|
||||
}
|
||||
if _, err := calculateProviderAmountMinor(command.USDMinorAmount, method.USDToCurrencyRate, method.CurrencyCode); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateV5PayMethodForTemporaryOrder(method ledger.ThirdPartyPaymentMethod, command ledger.CreateTemporaryExternalRechargeOrderCommand) error {
|
||||
if method.ProviderCode != ledger.PaymentProviderV5Pay || method.Status != ledger.ThirdPartyPaymentStatusActive || method.MethodID != command.PaymentMethodID {
|
||||
return xerr.New(xerr.Conflict, "v5pay method is not active")
|
||||
}
|
||||
if strings.TrimSpace(method.PayType) == "" {
|
||||
return xerr.New(xerr.InvalidArgument, "v5pay product type is required")
|
||||
}
|
||||
if _, err := calculateProviderAmountMinor(command.USDMinorAmount, method.USDToCurrencyRate, method.CurrencyCode); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isTemporaryExternalRechargeOrder(order ledger.ExternalRechargeOrder) bool {
|
||||
return order.AudienceType == ledger.RechargeAudienceTemporary || strings.HasPrefix(order.CommandID, "h5_temporary_recharge:")
|
||||
}
|
||||
@ -109,10 +109,13 @@ type ExternalRechargeStore interface {
|
||||
UpdateThirdPartyPaymentRate(ctx context.Context, command ledger.ThirdPartyPaymentRateCommand) (ledger.ThirdPartyPaymentMethod, error)
|
||||
GetThirdPartyPaymentMethod(ctx context.Context, appCode string, methodID int64) (ledger.ThirdPartyPaymentMethod, error)
|
||||
ListH5RechargeOptions(ctx context.Context, query ledger.H5RechargeOptionsQuery) (ledger.H5RechargeOptions, error)
|
||||
ListTemporaryExternalRechargeOrders(ctx context.Context, query ledger.ListTemporaryExternalRechargeOrdersQuery) ([]ledger.ExternalRechargeOrder, int64, error)
|
||||
CreateExternalRechargeOrder(ctx context.Context, command ledger.CreateExternalRechargeOrderCommand, product ledger.RechargeProduct, method *ledger.ThirdPartyPaymentMethod, providerAmountMinor int64, receiveAddress string) (ledger.ExternalRechargeOrder, error)
|
||||
CreateTemporaryExternalRechargeOrder(ctx context.Context, command ledger.CreateTemporaryExternalRechargeOrderCommand, method ledger.ThirdPartyPaymentMethod, providerAmountMinor int64) (ledger.ExternalRechargeOrder, error)
|
||||
MarkExternalRechargeOrderRedirected(ctx context.Context, appCode string, orderID string, providerOrderID string, payURL string, payloadJSON string) (ledger.ExternalRechargeOrder, error)
|
||||
AttachExternalRechargeTx(ctx context.Context, command ledger.SubmitExternalRechargeTxCommand, payloadJSON string) (ledger.ExternalRechargeOrder, error)
|
||||
CreditExternalRechargeOrder(ctx context.Context, appCode string, orderID string, providerOrderID string, txHash string, payloadJSON string) (ledger.ExternalRechargeOrder, error)
|
||||
MarkExternalRechargeOrderPaid(ctx context.Context, appCode string, orderID string, providerOrderID string, payloadJSON string) (ledger.ExternalRechargeOrder, error)
|
||||
MarkExternalRechargeOrderFailed(ctx context.Context, appCode string, orderID string, reason string, payloadJSON string) (ledger.ExternalRechargeOrder, error)
|
||||
GetExternalRechargeOrder(ctx context.Context, appCode string, orderID string) (ledger.ExternalRechargeOrder, error)
|
||||
ListExternalRechargeOrdersForReconcile(ctx context.Context, appCode string, limit int) ([]ledger.ExternalRechargeOrder, error)
|
||||
|
||||
@ -18,6 +18,7 @@ func (r *Repository) CreateExternalRechargeOrder(ctx context.Context, command le
|
||||
}
|
||||
ctx = contextWithCommandApp(ctx, command.AppCode)
|
||||
command.AppCode = appcode.FromContext(ctx)
|
||||
// 临时支付链接和正式 H5 充值共用 command_id 幂等约束;浏览器重试创建时必须返回同一笔订单,不能生成多个可支付链接。
|
||||
if existing, found, err := r.lookupExternalRechargeOrderByCommand(ctx, command.AppCode, command.CommandID); err != nil || found {
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
@ -44,6 +45,41 @@ func (r *Repository) CreateExternalRechargeOrder(ctx context.Context, command le
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *Repository) CreateTemporaryExternalRechargeOrder(ctx context.Context, command ledger.CreateTemporaryExternalRechargeOrderCommand, method ledger.ThirdPartyPaymentMethod, providerAmountMinor int64) (ledger.ExternalRechargeOrder, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return ledger.ExternalRechargeOrder{}, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
ctx = contextWithCommandApp(ctx, command.AppCode)
|
||||
command.AppCode = appcode.FromContext(ctx)
|
||||
if existing, found, err := r.lookupExternalRechargeOrderByCommand(ctx, command.AppCode, command.CommandID); err != nil || found {
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
existing.IdempotentReplay = true
|
||||
return existing, nil
|
||||
}
|
||||
|
||||
nowMS := time.Now().UnixMilli()
|
||||
// 同表保存能复用三方回调、查单和后台列表投影;target_user_id/product_id 置 0 表示这笔钱只供人工核销,不自动发金币。
|
||||
order := temporaryExternalRechargeOrderFromCommand(command, method, providerAmountMinor, nowMS)
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
INSERT INTO external_recharge_orders (
|
||||
app_code, order_id, command_id, target_user_id, target_region_id, target_country_code, audience_type,
|
||||
product_id, product_code, product_name, coin_amount, usd_minor_amount, provider_code, payment_method_id,
|
||||
country_code, currency_code, provider_amount_minor, pay_way, pay_type, receive_address, status,
|
||||
created_at_ms, updated_at_ms
|
||||
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
order.AppCode, order.OrderID, order.CommandID, order.TargetUserID, order.TargetRegionID, order.TargetCountryCode,
|
||||
order.AudienceType, order.ProductID, order.ProductCode, order.ProductName, order.CoinAmount, order.USDMinorAmount,
|
||||
order.ProviderCode, order.PaymentMethodID, order.CountryCode, order.CurrencyCode, order.ProviderAmountMinor,
|
||||
order.PayWay, order.PayType, order.ReceiveAddress, order.Status, order.CreatedAtMS, order.UpdatedAtMS,
|
||||
)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
return order, nil
|
||||
}
|
||||
|
||||
func (r *Repository) MarkExternalRechargeOrderRedirected(ctx context.Context, appCode string, orderID string, providerOrderID string, payURL string, payloadJSON string) (ledger.ExternalRechargeOrder, error) {
|
||||
ctx = contextWithCommandApp(ctx, appCode)
|
||||
nowMS := time.Now().UnixMilli()
|
||||
@ -241,14 +277,36 @@ func (r *Repository) CreditExternalRechargeOrder(ctx context.Context, appCode st
|
||||
return r.GetExternalRechargeOrder(ctx, order.AppCode, order.OrderID)
|
||||
}
|
||||
|
||||
func (r *Repository) MarkExternalRechargeOrderPaid(ctx context.Context, appCode string, orderID string, providerOrderID string, payloadJSON string) (ledger.ExternalRechargeOrder, error) {
|
||||
ctx = contextWithCommandApp(ctx, appCode)
|
||||
nowMS := time.Now().UnixMilli()
|
||||
// paid 是临时支付的终态:只确认三方已收款,不创建 wallet transaction,也不写充值记录,避免把内部临时收款误发给用户。
|
||||
result, err := r.db.ExecContext(ctx, `
|
||||
UPDATE external_recharge_orders
|
||||
SET status = ?, provider_order_id = CASE WHEN ? = '' THEN provider_order_id ELSE ? END, provider_payload = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND order_id = ? AND status NOT IN (?, ?)`,
|
||||
ledger.ExternalRechargeStatusPaid, strings.TrimSpace(providerOrderID), strings.TrimSpace(providerOrderID), nullableJSON(payloadJSON), nowMS,
|
||||
appcode.FromContext(ctx), strings.TrimSpace(orderID), ledger.ExternalRechargeStatusCredited, ledger.ExternalRechargeStatusFailed,
|
||||
)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
}
|
||||
if affected, err := result.RowsAffected(); err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
} else if affected == 0 {
|
||||
return r.GetExternalRechargeOrder(ctx, appcode.FromContext(ctx), orderID)
|
||||
}
|
||||
return r.GetExternalRechargeOrder(ctx, appcode.FromContext(ctx), orderID)
|
||||
}
|
||||
|
||||
func (r *Repository) MarkExternalRechargeOrderFailed(ctx context.Context, appCode string, orderID string, reason string, payloadJSON string) (ledger.ExternalRechargeOrder, error) {
|
||||
ctx = contextWithCommandApp(ctx, appCode)
|
||||
_, err := r.db.ExecContext(ctx, `
|
||||
UPDATE external_recharge_orders
|
||||
SET status = ?, failure_reason = ?, provider_payload = ?, updated_at_ms = ?
|
||||
WHERE app_code = ? AND order_id = ? AND status <> ?`,
|
||||
WHERE app_code = ? AND order_id = ? AND status NOT IN (?, ?)`,
|
||||
ledger.ExternalRechargeStatusFailed, trimMax(reason, 512), nullableJSON(payloadJSON), time.Now().UnixMilli(),
|
||||
appcode.FromContext(ctx), strings.TrimSpace(orderID), ledger.ExternalRechargeStatusCredited,
|
||||
appcode.FromContext(ctx), strings.TrimSpace(orderID), ledger.ExternalRechargeStatusCredited, ledger.ExternalRechargeStatusPaid,
|
||||
)
|
||||
if err != nil {
|
||||
return ledger.ExternalRechargeOrder{}, err
|
||||
@ -268,6 +326,37 @@ func (r *Repository) GetExternalRechargeOrder(ctx context.Context, appCode strin
|
||||
return order, err
|
||||
}
|
||||
|
||||
func (r *Repository) ListTemporaryExternalRechargeOrders(ctx context.Context, query ledger.ListTemporaryExternalRechargeOrdersQuery) ([]ledger.ExternalRechargeOrder, int64, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, 0, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
}
|
||||
ctx = contextWithCommandApp(ctx, query.AppCode)
|
||||
where, args := temporaryExternalRechargeOrdersWhere(appcode.FromContext(ctx), query)
|
||||
var total int64
|
||||
if err := r.db.QueryRowContext(ctx, `SELECT COUNT(*) FROM external_recharge_orders `+where, args...).Scan(&total); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
page, pageSize := normalizeTemporaryExternalRechargePage(query.Page, query.PageSize)
|
||||
rows, err := r.db.QueryContext(ctx, externalRechargeOrderSelectSQL()+`
|
||||
`+where+`
|
||||
ORDER BY created_at_ms DESC, order_id DESC
|
||||
LIMIT ? OFFSET ?`, append(args, pageSize, (page-1)*pageSize)...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
orders := make([]ledger.ExternalRechargeOrder, 0, pageSize)
|
||||
for rows.Next() {
|
||||
order, err := scanExternalRechargeOrder(rows)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
orders = append(orders, order)
|
||||
}
|
||||
return orders, total, rows.Err()
|
||||
}
|
||||
|
||||
func (r *Repository) ListExternalRechargeOrdersForReconcile(ctx context.Context, appCode string, limit int) ([]ledger.ExternalRechargeOrder, error) {
|
||||
if r == nil || r.db == nil {
|
||||
return nil, xerr.New(xerr.Unavailable, "mysql repository is not configured")
|
||||
@ -303,6 +392,38 @@ func (r *Repository) ListExternalRechargeOrdersForReconcile(ctx context.Context,
|
||||
return orders, rows.Err()
|
||||
}
|
||||
|
||||
func temporaryExternalRechargeOrdersWhere(appCode string, query ledger.ListTemporaryExternalRechargeOrdersQuery) (string, []any) {
|
||||
where := `WHERE app_code = ? AND audience_type = ?`
|
||||
args := []any{appCode, ledger.RechargeAudienceTemporary}
|
||||
if status := strings.TrimSpace(query.Status); status != "" {
|
||||
where += ` AND status = ?`
|
||||
args = append(args, status)
|
||||
}
|
||||
if providerCode := ledger.NormalizePaymentProvider(query.ProviderCode); providerCode != "" {
|
||||
where += ` AND provider_code = ?`
|
||||
args = append(args, providerCode)
|
||||
}
|
||||
if keyword := strings.TrimSpace(query.Keyword); keyword != "" {
|
||||
where += ` AND (order_id LIKE ? OR provider_order_id LIKE ?)`
|
||||
like := "%" + keyword + "%"
|
||||
args = append(args, like, like)
|
||||
}
|
||||
return where, args
|
||||
}
|
||||
|
||||
func normalizeTemporaryExternalRechargePage(page int32, pageSize int32) (int32, int32) {
|
||||
if page <= 0 {
|
||||
page = 1
|
||||
}
|
||||
if pageSize <= 0 {
|
||||
pageSize = 20
|
||||
}
|
||||
if pageSize > 100 {
|
||||
pageSize = 100
|
||||
}
|
||||
return page, pageSize
|
||||
}
|
||||
|
||||
func (r *Repository) lookupExternalRechargeOrderByCommand(ctx context.Context, appCode string, commandID string) (ledger.ExternalRechargeOrder, bool, error) {
|
||||
order, err := scanExternalRechargeOrder(r.db.QueryRowContext(ctx, externalRechargeOrderSelectSQL()+`
|
||||
WHERE app_code = ? AND command_id = ?`,
|
||||
@ -419,6 +540,41 @@ func externalRechargeOrderFromCommand(command ledger.CreateExternalRechargeOrder
|
||||
return order
|
||||
}
|
||||
|
||||
func temporaryExternalRechargeOrderFromCommand(command ledger.CreateTemporaryExternalRechargeOrderCommand, method ledger.ThirdPartyPaymentMethod, providerAmountMinor int64, nowMS int64) ledger.ExternalRechargeOrder {
|
||||
// 临时收款不绑定用户和商品,target/product 字段固定为 0,避免后续回调误入正式充值入账链路。
|
||||
return ledger.ExternalRechargeOrder{
|
||||
OrderID: externalRechargeOrderID(command.AppCode, command.CommandID),
|
||||
AppCode: command.AppCode,
|
||||
CommandID: strings.TrimSpace(command.CommandID),
|
||||
TargetUserID: 0,
|
||||
TargetRegionID: 0,
|
||||
TargetCountryCode: strings.ToUpper(strings.TrimSpace(method.CountryCode)),
|
||||
AudienceType: ledger.RechargeAudienceTemporary,
|
||||
ProductID: 0,
|
||||
ProductCode: "temporary",
|
||||
ProductName: temporaryExternalRechargeProductName(command.CoinAmount),
|
||||
CoinAmount: command.CoinAmount,
|
||||
USDMinorAmount: command.USDMinorAmount,
|
||||
ProviderCode: ledger.NormalizePaymentProvider(command.ProviderCode),
|
||||
PaymentMethodID: method.MethodID,
|
||||
CountryCode: method.CountryCode,
|
||||
CurrencyCode: method.CurrencyCode,
|
||||
ProviderAmountMinor: providerAmountMinor,
|
||||
PayWay: method.PayWay,
|
||||
PayType: method.PayType,
|
||||
Status: ledger.ExternalRechargeStatusPending,
|
||||
CreatedAtMS: nowMS,
|
||||
UpdatedAtMS: nowMS,
|
||||
}
|
||||
}
|
||||
|
||||
func temporaryExternalRechargeProductName(coinAmount int64) string {
|
||||
if coinAmount <= 0 {
|
||||
return "Temporary recharge"
|
||||
}
|
||||
return fmt.Sprintf("Temporary recharge %d coins", coinAmount)
|
||||
}
|
||||
|
||||
func externalRechargeOrderID(appCode string, commandID string) string {
|
||||
|
||||
return stableHash(appcode.Normalize(appCode) + "|" + strings.TrimSpace(commandID))[:32]
|
||||
|
||||
@ -113,6 +113,61 @@ func (s *Server) CreateH5RechargeOrder(ctx context.Context, req *walletv1.Create
|
||||
return &walletv1.H5RechargeOrderResponse{Order: externalRechargeOrderToProto(order)}, nil
|
||||
}
|
||||
|
||||
// CreateTemporaryRechargeOrder 创建运营临时支付链接;支付成功只标记 paid,不触发钱包入账。
|
||||
func (s *Server) CreateTemporaryRechargeOrder(ctx context.Context, req *walletv1.CreateTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
||||
order, err := s.svc.CreateTemporaryRechargeOrder(ctx, ledger.CreateTemporaryExternalRechargeOrderCommand{
|
||||
AppCode: req.GetAppCode(),
|
||||
CommandID: req.GetCommandId(),
|
||||
CoinAmount: req.GetCoinAmount(),
|
||||
USDMinorAmount: req.GetUsdMinorAmount(),
|
||||
ProviderCode: req.GetProviderCode(),
|
||||
PaymentMethodID: req.GetPaymentMethodId(),
|
||||
ReturnURL: req.GetReturnUrl(),
|
||||
NotifyURL: req.GetNotifyUrl(),
|
||||
ClientIP: req.GetClientIp(),
|
||||
Language: req.GetLanguage(),
|
||||
PayerName: req.GetPayerName(),
|
||||
PayerAccount: req.GetPayerAccount(),
|
||||
PayerEmail: req.GetPayerEmail(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &walletv1.H5RechargeOrderResponse{Order: externalRechargeOrderToProto(order)}, nil
|
||||
}
|
||||
|
||||
// GetTemporaryRechargeOrder 给运营页验证临时链接是否已支付,并顺带触发三方查单刷新状态。
|
||||
func (s *Server) GetTemporaryRechargeOrder(ctx context.Context, req *walletv1.GetTemporaryRechargeOrderRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
||||
order, err := s.svc.GetTemporaryRechargeOrder(ctx, req.GetAppCode(), req.GetOrderId())
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
return &walletv1.H5RechargeOrderResponse{Order: externalRechargeOrderToProto(order)}, nil
|
||||
}
|
||||
|
||||
// ListTemporaryRechargeOrders 返回后台临时支付链接列表;这里只读订单快照,不批量访问上游支付商。
|
||||
func (s *Server) ListTemporaryRechargeOrders(ctx context.Context, req *walletv1.ListTemporaryRechargeOrdersRequest) (*walletv1.ListTemporaryRechargeOrdersResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
||||
orders, total, err := s.svc.ListTemporaryRechargeOrders(ctx, ledger.ListTemporaryExternalRechargeOrdersQuery{
|
||||
AppCode: req.GetAppCode(),
|
||||
Status: req.GetStatus(),
|
||||
ProviderCode: req.GetProviderCode(),
|
||||
Keyword: req.GetKeyword(),
|
||||
Page: req.GetPage(),
|
||||
PageSize: req.GetPageSize(),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, xerr.ToGRPCError(err)
|
||||
}
|
||||
resp := &walletv1.ListTemporaryRechargeOrdersResponse{Orders: make([]*walletv1.ExternalRechargeOrder, 0, len(orders)), Total: total}
|
||||
for _, order := range orders {
|
||||
resp.Orders = append(resp.Orders, externalRechargeOrderToProto(order))
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
// SubmitH5RechargeTx 接收 USDT tx_hash;链上校验和幂等入账仍在 wallet-service 事务里完成。
|
||||
func (s *Server) SubmitH5RechargeTx(ctx context.Context, req *walletv1.SubmitH5RechargeTxRequest) (*walletv1.H5RechargeOrderResponse, error) {
|
||||
ctx = appcode.WithContext(ctx, req.GetAppCode())
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user